home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / trn / part05 < prev    next >
Encoding:
Internet Message Format  |  1991-12-02  |  78.2 KB

  1. Subject:  v25i008:  trn 2.0 - threaded newsreader based on rn 4.4, Part05/13
  2. Newsgroups: comp.sources.unix
  3. Approved: vixie@pa.dec.com
  4.  
  5. Submitted-by: davison@borland.com (Wayne Davison)
  6. Posting-number: Volume 25, Issue 8
  7. Archive-name: trn/part05
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 5 (of 13)."
  16. # Contents:  NEW getdate.y rcln.c search.c sw.c unship.c
  17. # Wrapped by vixie@cognition.pa.dec.com on Tue Dec  3 16:34:53 1991
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'NEW' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'NEW'\"
  21. else
  22. echo shar: Extracting \"'NEW'\" \(11839 characters\)
  23. sed "s/^X//" >'NEW' <<'END_OF_FILE'
  24. X            TRN 2.0 vs TRN 1.0.3:
  25. X
  26. X[If you're upgrading from trn 1.x, at least read the ** LOOK ** section.]
  27. X
  28. New commands:
  29. X
  30. X    g number    g command will go to a newsgroup by number where the
  31. X            the number corresponds to that used in the list 
  32. X            supplied by the 'L' command. (newsgroup level)
  33. X    z        supersede an article (article level)
  34. X    t        turn on/off run-time threading for a group that
  35. X            doesn't have a thread file (newsgroup level)
  36. X    A        abandon read/unread changes to the current newsgroup
  37. X            (newsgroup level)
  38. X
  39. New command-line options:
  40. X
  41. X    -a        use run-time threading to read all groups threaded
  42. X            (even those without a pre-built thread file)
  43. X    -o        use the old method of junking articles in the
  44. X            thread commands (they didn't follow the xrefs in
  45. X            trn 1.x)
  46. X    -o2        in addition to -o, don't use the database to make
  47. X            following of xrefs faster.  This is useful if your
  48. X            database is maintained by an old version of mthreads
  49. X            (pre-v2.0) -- you'll probably want to put this in
  50. X            the global INIT file if this is true.
  51. X
  52. New features:
  53. X
  54. X   o    Trn is now able to thread newsgroups at run-time.  This has two
  55. X    implications:  it is now possible to maintain a thread database
  56. X    for fewer groups (or none) and still take advantage of the threaded
  57. X    features of trn.  Also, when trn is used with a database, it will
  58. X    notice new articles that have not yet been processed by mthreads and
  59. X    incrementally thread them as soon as they arrive.  (This means that
  60. X    trn directly reads the active file -- active2 is a private file for
  61. X    mthreads now.)
  62. X   o    Trn has much faster and more accurate new-group-finding code that can
  63. X    be used if you (a) run C news, (b) run mthreads with the -t option,
  64. X    or (c) run trrn with a server that: (1) runs C news, (2) runs mthreads
  65. X    with the -t option, or (3) runs acttimes (provided), not mkgrdates.
  66. X   o    The 't' command on the newsgroup selection level is used to toggle
  67. X    whether the current group should be read threaded or not.  This
  68. X    is especially needed when the entire database does not have thread
  69. X    files, since it allows the user to choose the groups for which they
  70. X    want to have on-the-fly thread data generated.  Or use the -a option
  71. X    to force all unthreaded groups to be read as threaded.
  72. X   o    Mthreads now keeps track of which articles have xrefs in them so
  73. X    that trn can optimize the junking of articles.  This allows all
  74. X    article-junking commands to mark cross-referenced articles as read
  75. X    without a severe speed penalty.  (The one exception is 'c'atchup,
  76. X    which does not mark cross-references to keep it compatible.)
  77. X   o    The 'e' command will now repeat the previous extraction if it is
  78. X    followed by no options.  Thus, you can "e some/long/dir/name" and
  79. X    then use "e" to keep extracting to the same spot.  Use "e ." to
  80. X    extract back to the initial default of SAVEDIR.
  81. X   o    The uudecoder now understands "include" lines, and only allows a
  82. X    file with the correct 'part' sequence to be decoded next when they
  83. X    are used.
  84. X   o    There is now a built-in ship decoder (which is a better uuencode
  85. X    system).  They are automatically detected and extracted via the
  86. X    'e'xtract command.
  87. X   o    If you accidentally unsubscribe to a newsgroup, you can now use
  88. X    '-' to get back to it.
  89. X   o    The 'a pattern' command to add new newsgroups will now prompt for
  90. X    ALL unsubscribed newsgroups that match the pattern, whether they
  91. X    are in the newsrc file or not.
  92. X   o    You can now use the ',' command (mark article and all replies to
  93. X    this article as read) on a search or range command.  For example,
  94. X    you can put "/user name/h:," into your KILL file to wipe-out
  95. X    flame-fests started by articles from "user name".
  96. X   o    The 'f'ollow-up command (not 'F') has been changed to ask the
  97. X    user if this is a posting that is unrelated to the current article.
  98. X    This automatically clears the References line, sets the Newsgroups
  99. X    line properly, and prompts for the Subject: and Distributions: lines.
  100. X    In other words, all the things that would have been done if the
  101. X    user had remembered to use '$' before starting a new posting.
  102. X   o    On entry into a threaded group, trn now marks all missing articles
  103. X    as read.  This results in an accurate count when viewing the group
  104. X    at the newsgroup prompt.
  105. X   o    Changed the 'q' command in the thread selector to quit the group,
  106. X    not just exit the selector to the article level.  Use Esc or '+'
  107. X    for that.  See also the HINTS file for a macro to simulate the old
  108. X    behavior.
  109. X   o    The newsgroup line is now shown when it conflicts with the current
  110. X    group.  This is useful for looking through junk, and noticing groups
  111. X    that have been redirected using C news's '=' directive.
  112. X
  113. X
  114. Slight incompatibility in mthreads:    ** LOOK **
  115. X
  116. X   o    Since the -D option in mthreads was busted (it processed all groups
  117. X    instead of only the listed groups), and since people keep expecting
  118. X    "mthreads this.group" to only process one group, I've changed it
  119. X    to work this way.  The old behavior of "mthreads comp" (which would
  120. X    process all enabled groups while threading all existing and new comp
  121. X    groups) is achieved by first turning on all of comp with the above
  122. X    command, and then using the command "mthreads -a comp" to process all
  123. X    enabled groups and only add thread files for new comp groups.  The
  124. X    usage of the -a option without a hierarchy name hasn't changed --
  125. X    "mthreads -a" will still process all enabled groups and add all new
  126. X    groups (it is equivilent to the command "mthreads -a all").  The
  127. X    command "mthreads all" is a special case that just happens to work
  128. X    the same as before -- it turns on all existing groups, so it also
  129. X    processes all groups.  Also, remember that the -n option will skip
  130. X    processing the groups, so that you can use "mthreads -n rec,soc" to
  131. X    turn on all of rec and soc, and then startup an mthreads daemon to
  132. X    do the processing ("mthreads -dave" for example).  See the man page
  133. X    (which is now in its proper group: '8') for full details.
  134. X
  135. Changes to mthreads:
  136. X
  137. X   o    Mthreads has been enhanced to check its data more fully for file-
  138. X    corruption errors when reading in a thread file.  This should
  139. X    almost eliminate the SIGSEV or SIGBUS errors that would terminate
  140. X    mthreads' execution.
  141. X   o    Mthreads now has a separate lock file for the daemon and each
  142. X    update pass.  This allows you to run an mthreads daemon and still
  143. X    be able to execute single-pass commands when the daemon is sleeping.
  144. X   o    The enhanced-expiration code has been improved to run _much_ faster,
  145. X    especially for NNTP versions of mthreads.
  146. X   o    Mthreads puts its db.init file into the root of the THREAD_DIR
  147. X    (which might be SPOOL) to make sharing of the data via NFS easier.
  148. X   o    Mthreads now has an option to do all its logging using SYSLOG.
  149. X   o    Mthreads has some minor optimizations, which should (hopefully)
  150. X    offset the more extensive data checking.
  151. X   o    The -s option of mthreads has been extended to allow microseconds
  152. X    to be specified.  Using just -s will still delay for one second
  153. X    per article, as will -s1000000.  A portable version of usleep is
  154. X    included for sites that lack it.
  155. X
  156. X
  157. New environment variables:
  158. X    AUTOSUBSCRIBE    newsgroup pattern for groups to automatically
  159. X            subscribe to when found. Groups not matching
  160. X            are presented to the user via the usual
  161. X            subscription prompts.
  162. X    AUTOUNSUBSCRIBE newsgroup pattern for groups to not subscribe to.
  163. X            Groups matching this pattern are not subsribed to.
  164. X    REPLYTO        the value to use for the "Reply-To:" header, if
  165. X            needed.
  166. X    NEWSORG        Same as ORGANIZATION. Used for those sites that
  167. X            need ORGANIZATION for other purposes (Apollos).
  168. X    SUPERSEDEHEADER The header format to use for a 'z' command.
  169. X    LOCALTIMEFMT    An strftime specification for formatting the
  170. X            local-time output of the date header.
  171. X
  172. X
  173. Bug fixes:
  174. X
  175. X   o    Numbering of sibling articles that arrive out of order has been
  176. X    improved.  This is useful for groups like comp.sources.misc that
  177. X    thread common postings as one root article with the rest as
  178. X    immediate children.
  179. X   o    Fixed the save command to create intermediate directories.  Thus,
  180. X    "s src/newdir/file" will now create newdir instead of complaining.
  181. X   o    Fixed a case that could generate a report of negative articles
  182. X    left to read in trn.
  183. X   o    Fixed a bug in the thread selector that generated percentages
  184. X    greater than 100%.
  185. X   o    The .newsrc-writing code now checks more closely for errors in
  186. X    writing the file, to avoid having zero-length .newsrc's.
  187. X
  188. X   o    NNTP handling has been improved in mthreads.  One bug (expecting
  189. X    HEADers received via NNTP to have colons in them) would totally
  190. X    confuse mthreads -- now such bogus header lines are ignored.
  191. X   o    If a newsgroup is mentioned twice in the active file, mthreads
  192. X    would process it twice:  once with valid arguments, and once with
  193. X    0 for a high-article count.  This would result in a stream of
  194. X    "we've already seen article x" messages, and a negative "Added:"
  195. X    count.  It now complains about the bogus group and skips it.
  196. X
  197. X   o    When GETPWENT it defined and an invalid userid is used, an 
  198. X    error message is returned. Previously, trn would core dump.
  199. X   o    The newsgroups script now knows how to deal with "bogus" newsgroups.
  200. X    (These are groups in the active files marked with status 'x'.)
  201. X   o    If there is no news on trn startup and the user enters a "g" at
  202. X    the newsgroup level, the program will now correctly note that
  203. X    no newsgroup name has been entered and reprompt.
  204. X   o    Hostnames are now checked without respect to upper/lower case.
  205. X    This fixes a problem with the cancel command (academ.COM != academ.com
  206. X    before the fix).
  207. X   o    The NEWSADMIN code was buggy and often didn't work correctly.
  208. X    This has been fixed.
  209. X   o    %P is used to find a place for trrn to create active and article
  210. X    files. Previously, /tmp was hardcoded in most places.
  211. X   o    newsgroups would not remove the active file copy it made when 
  212. X    used via NNTP. Now it does remove this copy when it exits.
  213. X   o    Corrected some null pointer problems in the search code. Specifically,
  214. X    entering entering / or ? when there was no previous search pattern
  215. X    would cause a core dump. Now, it tells the user there there is
  216. X    no previous pattern.
  217. X   o    trrn now exits and leaves the terminal in a usable state when a
  218. X    server timeout occurs.
  219. X   o    trrn now supports the longest lines allowed by the NNTP RFC.
  220. X   o    trn will try to preseve permissions on .newsrc when it recreates
  221. X    it. Previously, it didn't do this.
  222. X   o    trn deals with NFS timeouts better. If the active file (on an NFS
  223. X    mounted partition) goes away, trn shuts down gracefully now.
  224. X
  225. X
  226. Configure improvements:
  227. X   o    Now uses nm to read contents of libc. ar is used if nm fails.
  228. X   o    The file config.h is now generated from config.h.SH instead of
  229. X    directly by the Configure script.  This allows the config.sh
  230. X    file to be edited (instead of both config.sh and config.h) and
  231. X    then 'make' will re-create config.h.
  232. X   o    Configure also provides the option of editing config.sh before
  233. X    config.h and all the shell scripts are created.
  234. X   o    Configure stores the origanization name in double quotes in
  235. X    config.sh. This avoids a problem with organization names that
  236. X    have single quotes in them (i.e. many French and Canadian 
  237. X    organizations).
  238. X   o    Configure now knows about RISC/os, Stardents and uts environments.
  239. X   o    Configure allows the specification of a compiler and extra
  240. X    compiler options.
  241. X   o    NNTP systems can now specify a system name rather than a filename
  242. X    to read the system name from.
  243. X
  244. X
  245. General improvements:
  246. X   o    Makes use of POSIX capabilities if present.
  247. X   o    ANSI C Compatible
  248. X   o    If __STDC__ is defined, we use the function prototypes.
  249. X   o    Hostname may be read in from a file instead of using system calls.
  250. X   o    ClariNet news headers are now recognized by trn. All header operations
  251. X    can be done on those headers.
  252. X   o    trn will dynamically allocate its structures to cope with any number
  253. X    of newsgroups in .newsrc or the active file.
  254. X   o    MMDF is now officially supported as a mail transfer agent.
  255. END_OF_FILE
  256. if test 11839 -ne `wc -c <'NEW'`; then
  257.     echo shar: \"'NEW'\" unpacked with wrong size!
  258. fi
  259. # end of 'NEW'
  260. fi
  261. if test -f 'getdate.y' -a "${1}" != "-c" ; then 
  262.   echo shar: Will not clobber existing file \"'getdate.y'\"
  263. else
  264. echo shar: Extracting \"'getdate.y'\" \(12374 characters\)
  265. sed "s/^X//" >'getdate.y' <<'END_OF_FILE'
  266. X%token ID MONTH DAY MERIDIAN NUMBER UNIT MUNIT SUNIT ZONE DAYZONE AGO
  267. X%{
  268. X    /*     Steven M. Bellovin (unc!smb)            */
  269. X    /*    Dept. of Computer Science            */
  270. X    /*    University of North Carolina at Chapel Hill    */
  271. X    /*    @(#)getdate.y    2.13    9/16/86 */
  272. X
  273. X#include <sys/types.h>
  274. X#include <ctype.h>
  275. X#include <time.h>
  276. X
  277. X#define    NULL    0
  278. X
  279. X#define daysec (24L*60L*60L)
  280. X
  281. X    static int timeflag, zoneflag, dateflag, dayflag, relflag;
  282. X    static time_t relsec, relmonth;
  283. X    static int hh, mm, ss, merid, daylight;
  284. X    static int dayord, dayreq;
  285. X    static int month, day, year;
  286. X    static int ourzone;
  287. X
  288. X#define AM 1
  289. X#define PM 2
  290. X#define DAYLIGHT 1
  291. X#define STANDARD 2
  292. X#define MAYBE    3
  293. X%}
  294. X
  295. X%%
  296. timedate:         /* empty */
  297. X    | timedate item;
  298. X
  299. item:    tspec =
  300. X        {timeflag++;}
  301. X    | zone =
  302. X        {zoneflag++;}
  303. X    | dtspec =
  304. X        {dateflag++;}
  305. X    | dyspec =
  306. X        {dayflag++;}
  307. X    | rspec =
  308. X        {relflag++;}
  309. X    | nspec;
  310. X
  311. nspec:    NUMBER =
  312. X        {if (timeflag && dateflag && !relflag) year = $1;
  313. X        else {timeflag++;hh = $1/100;mm = $1%100;ss = 0;merid = 24;}};
  314. X
  315. tspec:    NUMBER MERIDIAN =
  316. X        {hh = $1; mm = 0; ss = 0; merid = $2;}
  317. X    | NUMBER ':' NUMBER =
  318. X        {hh = $1; mm = $3; merid = 24;}
  319. X    | NUMBER ':' NUMBER MERIDIAN =
  320. X        {hh = $1; mm = $3; merid = $4;}
  321. X    | NUMBER ':' NUMBER NUMBER =
  322. X        {hh = $1; mm = $3; merid = 24;
  323. X        daylight = STANDARD; ourzone = -($4%100 + 60*$4/100);}
  324. X    | NUMBER ':' NUMBER ':' NUMBER =
  325. X        {hh = $1; mm = $3; ss = $5; merid = 24;}
  326. X    | NUMBER ':' NUMBER ':' NUMBER MERIDIAN =
  327. X        {hh = $1; mm = $3; ss = $5; merid = $6;}
  328. X    | NUMBER ':' NUMBER ':' NUMBER NUMBER =
  329. X        {hh = $1; mm = $3; ss = $5; merid = 24;
  330. X        daylight = STANDARD; ourzone = -($6%100 + 60*$6/100);};
  331. X
  332. zone:    ZONE =
  333. X        {ourzone = $1; daylight = STANDARD;}
  334. X    | DAYZONE =
  335. X        {ourzone = $1; daylight = DAYLIGHT;};
  336. X
  337. dyspec:    DAY =
  338. X        {dayord = 1; dayreq = $1;}
  339. X    | DAY ',' =
  340. X        {dayord = 1; dayreq = $1;}
  341. X    | NUMBER DAY =
  342. X        {dayord = $1; dayreq = $2;};
  343. X
  344. dtspec:    NUMBER '/' NUMBER =
  345. X        {month = $1; day = $3;}
  346. X    | NUMBER '/' NUMBER '/' NUMBER =
  347. X        {month = $1; day = $3; year = $5;}
  348. X    | MONTH NUMBER =
  349. X        {month = $1; day = $2;}
  350. X    | MONTH NUMBER ',' NUMBER =
  351. X        {month = $1; day = $2; year = $4;}
  352. X    | NUMBER MONTH =
  353. X        {month = $2; day = $1;}
  354. X    | NUMBER MONTH NUMBER =
  355. X        {month = $2; day = $1; year = $3;};
  356. X
  357. X
  358. rspec:    NUMBER UNIT =
  359. X        {relsec +=  60L * $1 * $2;}
  360. X    | NUMBER MUNIT =
  361. X        {relmonth += $1 * $2;}
  362. X    | NUMBER SUNIT =
  363. X        {relsec += $1;}
  364. X    | UNIT =
  365. X        {relsec +=  60L * $1;}
  366. X    | MUNIT =
  367. X        {relmonth += $1;}
  368. X    | SUNIT =
  369. X        {relsec++;}
  370. X    | rspec AGO =
  371. X        {relsec = -relsec; relmonth = -relmonth;};
  372. X%%
  373. X
  374. static int mdays[12] =
  375. X    {31, 0, 31,  30, 31, 30,  31, 31, 30,  31, 30, 31};
  376. X#define epoch 1970
  377. X
  378. extern struct tm *localtime();
  379. time_t dateconv(mm, dd, yy, h, m, s, mer, zone, dayflag)
  380. int mm, dd, yy, h, m, s, mer, zone, dayflag;
  381. X{
  382. X    time_t tod, jdate;
  383. X    register int i;
  384. X    time_t timeconv();
  385. X
  386. X    if (yy < 0) yy = -yy;
  387. X    if (yy < 100) yy += 1900;
  388. X    mdays[1] = 28 + (yy%4 == 0 && (yy%100 != 0 || yy%400 == 0));
  389. X    if (yy < epoch || yy > 1999 || mm < 1 || mm > 12 ||
  390. X        dd < 1 || dd > mdays[--mm]) return (-1);
  391. X    jdate = dd-1;
  392. X        for (i=0; i<mm; i++) jdate += mdays[i];
  393. X    for (i = epoch; i < yy; i++) jdate += 365 + (i%4 == 0);
  394. X    jdate *= daysec;
  395. X    jdate += zone * 60L;
  396. X    if ((tod = timeconv(h, m, s, mer)) < 0) return (-1);
  397. X    jdate += tod;
  398. X    if (dayflag==DAYLIGHT || (dayflag==MAYBE&&localtime(&jdate)->tm_isdst))
  399. X        jdate += -1*60*60;
  400. X    return (jdate);
  401. X}
  402. X
  403. time_t dayconv(ord, day, now) int ord, day; time_t now;
  404. X{
  405. X    register struct tm *loctime;
  406. X    time_t tod;
  407. X    time_t daylcorr();
  408. X
  409. X    tod = now;
  410. X    loctime = localtime(&tod);
  411. X    tod += daysec * ((day - loctime->tm_wday + 7) % 7);
  412. X    tod += 7*daysec*(ord<=0?ord:ord-1);
  413. X    return daylcorr(tod, now);
  414. X}
  415. X
  416. time_t timeconv(hh, mm, ss, mer) register int hh, mm, ss, mer;
  417. X{
  418. X    if (mm < 0 || mm > 59 || ss < 0 || ss > 59) return (-1);
  419. X    switch (mer) {
  420. X        case AM: if (hh < 1 || hh > 12) return(-1);
  421. X             return (60L * ((hh%12)*60L + mm)+ss);
  422. X        case PM: if (hh < 1 || hh > 12) return(-1);
  423. X             return (60L * ((hh%12 +12)*60L + mm)+ss);
  424. X        case 24: if (hh < 0 || hh > 23) return (-1);
  425. X             return (60L * (hh*60L + mm)+ss);
  426. X        default: return (-1);
  427. X    }
  428. X}
  429. time_t monthadd(sdate, relmonth) time_t sdate, relmonth;
  430. X{
  431. X    struct tm *ltime;
  432. X    time_t dateconv();
  433. X    time_t daylcorr();
  434. X    int mm, yy;
  435. X
  436. X    if (relmonth == 0) return 0;
  437. X    ltime = localtime(&sdate);
  438. X    mm = 12*ltime->tm_year + ltime->tm_mon + relmonth;
  439. X    yy = mm/12;
  440. X    mm = mm%12 + 1;
  441. X    return daylcorr(dateconv(mm, ltime->tm_mday, yy, ltime->tm_hour,
  442. X        ltime->tm_min, ltime->tm_sec, 24, ourzone, MAYBE), sdate);
  443. X}
  444. X
  445. time_t daylcorr(future, now) time_t future, now;
  446. X{
  447. X    int fdayl, nowdayl;
  448. X
  449. X    nowdayl = (localtime(&now)->tm_hour+1) % 24;
  450. X    fdayl = (localtime(&future)->tm_hour+1) % 24;
  451. X    return (future-now) + 60L*60L*(nowdayl-fdayl);
  452. X}
  453. X
  454. static char *lptr;
  455. X
  456. yylex()
  457. X{
  458. X    extern int yylval;
  459. X    int sign;
  460. X    register char c;
  461. X    register char *p;
  462. X    char idbuf[20];
  463. X    int pcnt;
  464. X
  465. X    for (;;) {
  466. X        while (isspace(*lptr)) lptr++;
  467. X
  468. X        if (isdigit(c = *lptr) || c == '-' || c == '+') {
  469. X            if (c== '-' || c == '+') {
  470. X                if (c=='-') sign = -1;
  471. X                else sign = 1;
  472. X                if (!isdigit(*++lptr)) {
  473. X                    /* yylval = sign; return (NUMBER); */
  474. X                    return yylex();    /* skip the '-' sign */
  475. X                }
  476. X            } else sign = 1;
  477. X            yylval = 0;
  478. X            while (isdigit(c = *lptr++)) yylval = 10*yylval + c - '0';
  479. X            yylval *= sign;
  480. X            lptr--;
  481. X            return (NUMBER);
  482. X
  483. X        } else if (isalpha(c)) {
  484. X            p = idbuf;
  485. X            while (isalpha(c = *lptr++) || c=='.')
  486. X                if (p < &idbuf[sizeof(idbuf)-1])
  487. X                    *p++ = c;
  488. X            *p = '\0';
  489. X            lptr--;
  490. X            return (lookup(idbuf));
  491. X        }
  492. X
  493. X        else if (c == '(') {
  494. X            pcnt = 0;
  495. X            do {
  496. X                c = *lptr++;
  497. X                if (c == '\0') return(c);
  498. X                else if (c == '(') pcnt++;
  499. X                else if (c == ')') pcnt--;
  500. X            } while (pcnt > 0);
  501. X        }
  502. X
  503. X        else return (*lptr++);
  504. X    }
  505. X}
  506. X
  507. struct table {
  508. X    char *name;
  509. X    int type, value;
  510. X};
  511. X
  512. struct table mdtab[] = {
  513. X    {"January", MONTH, 1},
  514. X    {"February", MONTH, 2},
  515. X    {"March", MONTH, 3},
  516. X    {"April", MONTH, 4},
  517. X    {"May", MONTH, 5},
  518. X    {"June", MONTH, 6},
  519. X    {"July", MONTH, 7},
  520. X    {"August", MONTH, 8},
  521. X    {"September", MONTH, 9},
  522. X    {"Sept", MONTH, 9},
  523. X    {"October", MONTH, 10},
  524. X    {"November", MONTH, 11},
  525. X    {"December", MONTH, 12},
  526. X
  527. X    {"Sunday", DAY, 0},
  528. X    {"Monday", DAY, 1},
  529. X    {"Tuesday", DAY, 2},
  530. X    {"Tues", DAY, 2},
  531. X    {"Wednesday", DAY, 3},
  532. X    {"Wednes", DAY, 3},
  533. X    {"Thursday", DAY, 4},
  534. X    {"Thur", DAY, 4},
  535. X    {"Thurs", DAY, 4},
  536. X    {"Friday", DAY, 5},
  537. X    {"Saturday", DAY, 6},
  538. X    {0, 0, 0}};
  539. X
  540. X#define HRS *60
  541. X#define HALFHR 30
  542. struct table mztab[] = {
  543. X    {"a.m.", MERIDIAN, AM},
  544. X    {"am", MERIDIAN, AM},
  545. X    {"p.m.", MERIDIAN, PM},
  546. X    {"pm", MERIDIAN, PM},
  547. X    {"nst", ZONE, 3 HRS + HALFHR},        /* Newfoundland */
  548. X    {"n.s.t.", ZONE, 3 HRS + HALFHR},
  549. X    {"ast", ZONE, 4 HRS},        /* Atlantic */
  550. X    {"a.s.t.", ZONE, 4 HRS},
  551. X    {"adt", DAYZONE, 4 HRS},
  552. X    {"a.d.t.", DAYZONE, 4 HRS},
  553. X    {"est", ZONE, 5 HRS},        /* Eastern */
  554. X    {"e.s.t.", ZONE, 5 HRS},
  555. X    {"edt", DAYZONE, 5 HRS},
  556. X    {"e.d.t.", DAYZONE, 5 HRS},
  557. X    {"cst", ZONE, 6 HRS},        /* Central */
  558. X    {"c.s.t.", ZONE, 6 HRS},
  559. X    {"cdt", DAYZONE, 6 HRS},
  560. X    {"c.d.t.", DAYZONE, 6 HRS},
  561. X    {"mst", ZONE, 7 HRS},        /* Mountain */
  562. X    {"m.s.t.", ZONE, 7 HRS},
  563. X    {"mdt", DAYZONE, 7 HRS},
  564. X    {"m.d.t.", DAYZONE, 7 HRS},
  565. X    {"pst", ZONE, 8 HRS},        /* Pacific */
  566. X    {"p.s.t.", ZONE, 8 HRS},
  567. X    {"pdt", DAYZONE, 8 HRS},
  568. X    {"p.d.t.", DAYZONE, 8 HRS},
  569. X    {"yst", ZONE, 9 HRS},        /* Yukon */
  570. X    {"y.s.t.", ZONE, 9 HRS},
  571. X    {"ydt", DAYZONE, 9 HRS},
  572. X    {"y.d.t.", DAYZONE, 9 HRS},
  573. X    {"hst", ZONE, 10 HRS},        /* Hawaii */
  574. X    {"h.s.t.", ZONE, 10 HRS},
  575. X    {"hdt", DAYZONE, 10 HRS},
  576. X    {"h.d.t.", DAYZONE, 10 HRS},
  577. X
  578. X    {"gmt", ZONE, 0 HRS},
  579. X    {"g.m.t.", ZONE, 0 HRS},
  580. X    {"bst", DAYZONE, 0 HRS},        /* British Summer Time */
  581. X    {"b.s.t.", DAYZONE, 0 HRS},
  582. X    {"eet", ZONE, 0 HRS},        /* European Eastern Time */
  583. X    {"e.e.t.", ZONE, 0 HRS},
  584. X    {"eest", DAYZONE, 0 HRS},    /* European Eastern Summer Time */
  585. X    {"e.e.s.t.", DAYZONE, 0 HRS},
  586. X    {"met", ZONE, -1 HRS},        /* Middle European Time */
  587. X    {"m.e.t.", ZONE, -1 HRS},
  588. X    {"mest", DAYZONE, -1 HRS},    /* Middle European Summer Time */
  589. X    {"m.e.s.t.", DAYZONE, -1 HRS},
  590. X    {"wet", ZONE, -2 HRS },        /* Western European Time */
  591. X    {"w.e.t.", ZONE, -2 HRS },
  592. X    {"west", DAYZONE, -2 HRS},    /* Western European Summer Time */
  593. X    {"w.e.s.t.", DAYZONE, -2 HRS},
  594. X
  595. X    {"jst", ZONE, -9 HRS},        /* Japan Standard Time */
  596. X    {"j.s.t.", ZONE, -9 HRS},    /* Japan Standard Time */
  597. X                    /* No daylight savings time */
  598. X
  599. X    {"aest", ZONE, -10 HRS},    /* Australian Eastern Time */
  600. X    {"a.e.s.t.", ZONE, -10 HRS},
  601. X    {"aesst", DAYZONE, -10 HRS},    /* Australian Eastern Summer Time */
  602. X    {"a.e.s.s.t.", DAYZONE, -10 HRS},
  603. X    {"acst", ZONE, -(9 HRS + HALFHR)},    /* Australian Central Time */
  604. X    {"a.c.s.t.", ZONE, -(9 HRS + HALFHR)},
  605. X    {"acsst", DAYZONE, -(9 HRS + HALFHR)},    /* Australian Central Summer */
  606. X    {"a.c.s.s.t.", DAYZONE, -(9 HRS + HALFHR)},
  607. X    {"awst", ZONE, -8 HRS},        /* Australian Western Time */
  608. X    {"a.w.s.t.", ZONE, -8 HRS},    /* (no daylight time there, I'm told */
  609. X    {0, 0, 0}};
  610. X
  611. struct table unittb[] = {
  612. X    {"year", MUNIT, 12},
  613. X    {"month", MUNIT, 1},
  614. X    {"fortnight", UNIT, 14*24*60},
  615. X    {"week", UNIT, 7*24*60},
  616. X    {"day", UNIT, 1*24*60},
  617. X    {"hour", UNIT, 60},
  618. X    {"minute", UNIT, 1},
  619. X    {"min", UNIT, 1},
  620. X    {"second", SUNIT, 1},
  621. X    {"sec", SUNIT, 1},
  622. X    {0, 0, 0}};
  623. X
  624. struct table othertb[] = {
  625. X    {"tomorrow", UNIT, 1*24*60},
  626. X    {"yesterday", UNIT, -1*24*60},
  627. X    {"today", UNIT, 0},
  628. X    {"now", UNIT, 0},
  629. X    {"last", NUMBER, -1},
  630. X    {"this", UNIT, 0},
  631. X    {"next", NUMBER, 2},
  632. X    {"first", NUMBER, 1},
  633. X    /* {"second", NUMBER, 2}, */
  634. X    {"third", NUMBER, 3},
  635. X    {"fourth", NUMBER, 4},
  636. X    {"fifth", NUMBER, 5},
  637. X    {"sixth", NUMBER, 6},
  638. X    {"seventh", NUMBER, 7},
  639. X    {"eigth", NUMBER, 8},
  640. X    {"ninth", NUMBER, 9},
  641. X    {"tenth", NUMBER, 10},
  642. X    {"eleventh", NUMBER, 11},
  643. X    {"twelfth", NUMBER, 12},
  644. X    {"ago", AGO, 1},
  645. X    {0, 0, 0}};
  646. X
  647. struct table milzone[] = {
  648. X    {"a", ZONE, 1 HRS},
  649. X    {"b", ZONE, 2 HRS},
  650. X    {"c", ZONE, 3 HRS},
  651. X    {"d", ZONE, 4 HRS},
  652. X    {"e", ZONE, 5 HRS},
  653. X    {"f", ZONE, 6 HRS},
  654. X    {"g", ZONE, 7 HRS},
  655. X    {"h", ZONE, 8 HRS},
  656. X    {"i", ZONE, 9 HRS},
  657. X    {"k", ZONE, 10 HRS},
  658. X    {"l", ZONE, 11 HRS},
  659. X    {"m", ZONE, 12 HRS},
  660. X    {"n", ZONE, -1 HRS},
  661. X    {"o", ZONE, -2 HRS},
  662. X    {"p", ZONE, -3 HRS},
  663. X    {"q", ZONE, -4 HRS},
  664. X    {"r", ZONE, -5 HRS},
  665. X    {"s", ZONE, -6 HRS},
  666. X    {"t", ZONE, -7 HRS},
  667. X    {"u", ZONE, -8 HRS},
  668. X    {"v", ZONE, -9 HRS},
  669. X    {"w", ZONE, -10 HRS},
  670. X    {"x", ZONE, -11 HRS},
  671. X    {"y", ZONE, -12 HRS},
  672. X    {"z", ZONE, 0 HRS},
  673. X    {0, 0, 0}};
  674. X
  675. lookup(id) char *id;
  676. X{
  677. X#define gotit (yylval=i->value,  i->type)
  678. X#define getid for(j=idvar, k=id; *j++ = *k++; )
  679. X
  680. X    char idvar[20];
  681. X    register char *j, *k;
  682. X    register struct table *i;
  683. X    int abbrev;
  684. X
  685. X    getid;
  686. X    if (strlen(idvar) == 3) abbrev = 1;
  687. X    else if (strlen(idvar) == 4 && idvar[3] == '.') {
  688. X        abbrev = 1;
  689. X        idvar[3] = '\0';
  690. X    }
  691. X    else abbrev = 0;
  692. X
  693. X    if (islower(*idvar)) *idvar = toupper(*idvar);
  694. X
  695. X    for (i = mdtab; i->name; i++) {
  696. X        k = idvar;
  697. X        for (j = i->name; *j++ == *k++;) {
  698. X            if (abbrev && j==i->name+3) return gotit;
  699. X            if (j[-1] == 0) return gotit;
  700. X        }
  701. X    }
  702. X
  703. X    getid;
  704. X    for (i = mztab; i->name; i++)
  705. X        if (strcmp(i->name, idvar) == 0) return gotit;
  706. X
  707. X    for (j = idvar; *j; j++)
  708. X        if (isupper(*j)) *j = tolower(*j);
  709. X    for (i=mztab; i->name; i++)
  710. X        if (strcmp(i->name, idvar) == 0) return gotit;
  711. X
  712. X    getid;
  713. X    for (i=unittb; i->name; i++)
  714. X        if (strcmp(i->name, idvar) == 0) return gotit;
  715. X
  716. X    if (idvar[strlen(idvar)-1] == 's')
  717. X        idvar[strlen(idvar)-1] = '\0';
  718. X    for (i=unittb; i->name; i++)
  719. X        if (strcmp(i->name, idvar) == 0) return gotit;
  720. X
  721. X    getid;
  722. X    for (i = othertb; i->name; i++)
  723. X        if (strcmp(i->name, idvar) == 0) return gotit;
  724. X
  725. X    getid;
  726. X    if (strlen(idvar) == 1 && isalpha(*idvar)) {
  727. X        if (isupper(*idvar)) *idvar = tolower(*idvar);
  728. X        for (i = milzone; i->name; i++)
  729. X            if (strcmp(i->name, idvar) == 0) return gotit;
  730. X    }
  731. X
  732. X    return(ID);
  733. X}
  734. X
  735. time_t get_date(p, now, zone) char *p; time_t now; long zone;
  736. X{
  737. X#define mcheck(f)    if (f>1) err++
  738. X    time_t monthadd();
  739. X    int err;
  740. X    struct tm *lt;
  741. X    time_t sdate, tod;
  742. X
  743. X    lptr = p;
  744. X    if (now <= 0)
  745. X        (void) time(&now);
  746. X    lt = localtime(&now);
  747. X    year = lt->tm_year;
  748. X    month = lt->tm_mon+1;
  749. X    day = lt->tm_mday;
  750. X    relsec = 0; relmonth = 0;
  751. X    timeflag=zoneflag=dateflag=dayflag=relflag=0;
  752. X    daylight = MAYBE;
  753. X    hh = mm = ss = 0;
  754. X    merid = 24;
  755. X    ourzone = zone;
  756. X
  757. X    if (err = yyparse()) return (-1);
  758. X
  759. X    mcheck(timeflag);
  760. X    mcheck(zoneflag);
  761. X    mcheck(dateflag);
  762. X    mcheck(dayflag);
  763. X
  764. X    if (err) return (-1);
  765. X    if (dateflag || timeflag || dayflag) {
  766. X        sdate = dateconv(month,day,year,hh,mm,ss,merid,ourzone,daylight);
  767. X        if (sdate < 0) return -1;
  768. X    }
  769. X    else {
  770. X        sdate = now;
  771. X        if (relflag == 0)
  772. X            sdate -= (lt->tm_sec + lt->tm_min*60 +
  773. X                lt->tm_hour*(60L*60L));
  774. X    }
  775. X
  776. X    sdate += relsec;
  777. X    sdate += monthadd(sdate, relmonth);
  778. X
  779. X    if (dayflag && !dateflag) {
  780. X        tod = dayconv(dayord, dayreq, sdate);
  781. X        sdate += tod;
  782. X    }
  783. X
  784. X    return sdate;
  785. X}
  786. X
  787. yyerror(s) char *s;
  788. X{}
  789. END_OF_FILE
  790. if test 12374 -ne `wc -c <'getdate.y'`; then
  791.     echo shar: \"'getdate.y'\" unpacked with wrong size!
  792. fi
  793. # end of 'getdate.y'
  794. fi
  795. if test -f 'rcln.c' -a "${1}" != "-c" ; then 
  796.   echo shar: Will not clobber existing file \"'rcln.c'\"
  797. else
  798. echo shar: Extracting \"'rcln.c'\" \(13041 characters\)
  799. sed "s/^X//" >'rcln.c' <<'END_OF_FILE'
  800. X/* $Id: rcln.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  801. X *
  802. X * $Log: rcln.c,v $
  803. X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  804. X * Patchlevel 2 changes
  805. X *
  806. X * Revision 4.4.1.1  1991/09/25  19:38:08  sob
  807. X * Some adaptions for CNEWS
  808. X *
  809. X * Revision 4.4  1991/09/09  20:27:37  sob
  810. X * release 4.4
  811. X *
  812. X *
  813. X * 
  814. X */
  815. X/* This software is Copyright 1991 by Stan Barber. 
  816. X *
  817. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  818. X * use this software as long as: there is no monetary profit gained
  819. X * specifically from the use or reproduction of this software, it is not
  820. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  821. X * included prominently in any copy made. 
  822. X *
  823. X * The author make no claims as to the fitness or correctness of this software
  824. X * for any use whatsoever, and it is provided as is. Any use of this software
  825. X * is at the user's own risk. 
  826. X */
  827. X
  828. X#include "EXTERN.h"
  829. X#include "common.h"
  830. X#include "util.h"
  831. X#include "rcstuff.h"
  832. X#include "ngdata.h"
  833. X#include "INTERN.h"
  834. X#include "rcln.h"
  835. X
  836. void
  837. rcln_init()
  838. X{
  839. X    ;
  840. X}
  841. X
  842. X#ifdef CATCHUP
  843. void
  844. catch_up(ngx)
  845. NG_NUM ngx;
  846. X{
  847. X    char tmpbuf[128];
  848. X    
  849. X#ifdef VERBOSE
  850. X    IF(verbose)
  851. X    printf("\nMarking %s as all read.\n",rcline[ngx]) FLUSH;
  852. X    ELSE
  853. X#endif
  854. X#ifdef TERSE
  855. X    fputs("\nMarked read\n",stdout) FLUSH;
  856. X#endif
  857. X    sprintf(tmpbuf,"%s: 1-%ld", rcline[ngx],(long)getngsize(ngx));
  858. X    free(rcline[ngx]);
  859. X    rcline[ngx] = savestr(tmpbuf);
  860. X    *(rcline[ngx] + rcnums[ngx] - 1) = '\0';
  861. X    toread[ngx] = TR_NONE;
  862. X    write_rc();
  863. X}
  864. X#endif
  865. X
  866. X/* add an article number to a newsgroup, if it isn't already read */
  867. X
  868. int
  869. addartnum(artnum,ngnam)
  870. ART_NUM artnum;
  871. char *ngnam;
  872. X{
  873. X    register NG_NUM ngnum = find_ng(ngnam);
  874. X    register char *s, *t, *maxt = Nullch;
  875. X    ART_NUM min = 0, max = -1, lastnum = 0;
  876. X    char *mbuf;
  877. X    bool morenum;
  878. X
  879. X    if (!artnum)
  880. X    return 0;
  881. X    if (ngnum == nextrcline || !rcnums[ngnum])
  882. X                    /* not found in newsrc? */
  883. X    return 0;
  884. X#ifdef CACHEFIRST
  885. X    if (!abs1st[ngnum])
  886. X#else
  887. X    if (!toread[ngnum])
  888. X#endif
  889. X#if !defined(SERVER) || defined(MININACT)
  890. X                    /* now is a good time to trim down */
  891. X    set_toread(ngnum);        /* the list due to expires if we */
  892. X                    /* have not yet. */
  893. X#endif
  894. X#ifdef DEBUGGING
  895. X    if (artnum > ngmax[ngnum] + 100    /* allow for incoming articles */
  896. X       ) {
  897. X    printf("\nCorrupt Xref line!!!  %ld --> %s(1..%ld)\n",
  898. X        artnum,ngnam,
  899. X        ngmax[ngnum]) FLUSH;
  900. X    paranoid = TRUE;        /* paranoia reigns supreme */
  901. X    return -1;            /* hope this was the first newsgroup */
  902. X    }
  903. X#endif
  904. X
  905. X    if (toread[ngnum] == TR_BOGUS)
  906. X    return 0;
  907. X#ifdef DEBUGGING
  908. X    if (debug & DEB_XREF_MARKER) {
  909. X    printf("%ld->\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  910. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  911. X    }
  912. X#endif
  913. X    s = rcline[ngnum] + rcnums[ngnum];
  914. X    while (*s == ' ') s++;        /* skip spaces */
  915. X    t = s;
  916. X    while (isdigit(*s) && artnum >= (min = atol(s))) {
  917. X                    /* while it might have been read */
  918. X    for (t = s; isdigit(*t); t++) ;    /* skip number */
  919. X    if (*t == '-') {        /* is it a range? */
  920. X        t++;            /* skip to next number */
  921. X        if (artnum <= (max = atol(t)))
  922. X        return 0;        /* it is in range => already read */
  923. X        lastnum = max;        /* remember it */
  924. X        maxt = t;            /* remember position in case we */
  925. X                    /* want to overwrite the max */
  926. X        while (isdigit(*t)) t++;    /* skip second number */
  927. X    }
  928. X    else {
  929. X        if (artnum == min)        /* explicitly a read article? */
  930. X        return 0;
  931. X        lastnum = min;        /* remember what the number was */
  932. X        maxt = Nullch;        /* last one was not a range */
  933. X    }
  934. X    while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  935. X    s = t;
  936. X    }
  937. X    
  938. X    /* we have not read it, so insert the article number before s */
  939. X    
  940. X    morenum = isdigit(*s);        /* will it need a comma after? */
  941. X#ifdef USETHREADS
  942. X    *(rcline[ngnum] + rcnums[ngnum] - 1) = RCCHAR(rcchar[ngnum]);
  943. X#else
  944. X    *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  945. X#endif
  946. X    mbuf = safemalloc((MEM_SIZE)(strlen(s) + (s-rcline[ngnum]) + 8));
  947. X    strcpy(mbuf,rcline[ngnum]);        /* make new rc line */
  948. X    if (maxt && lastnum && artnum == lastnum+1)
  949. X                        /* can we just extend last range? */
  950. X    t = mbuf + (maxt-rcline[ngnum]);/* then overwrite previous max */
  951. X    else {
  952. X    t = mbuf + (t-rcline[ngnum]);    /* point t into new line instead */
  953. X    if (lastnum) {            /* have we parsed any line? */
  954. X        if (!morenum)        /* are we adding to the tail? */
  955. X        *t++ = ',';        /* supply comma before */
  956. X        if (!maxt && artnum == lastnum+1 && *(t-1) == ',')
  957. X                    /* adjacent singletons? */
  958. X        *(t-1) = '-';        /* turn them into a range */
  959. X    }
  960. X    }
  961. X    if (morenum) {            /* is there more to life? */
  962. X    if (min == artnum+1) {        /* can we consolidate further? */
  963. X        bool range_before = (*(t-1) == '-');
  964. X        bool range_after;
  965. X        char *nextmax;
  966. X
  967. X        for (nextmax = s; isdigit(*nextmax); nextmax++) ;
  968. X        range_after = *nextmax++ == '-';
  969. X        
  970. X        if (range_before)
  971. X        *t = '\0';        /* artnum is redundant */
  972. X        else
  973. X        sprintf(t,"%ld-",(long)artnum);/* artnum will be new min */
  974. X        
  975. X        if (range_after)
  976. X        s = nextmax;        /* *s is redundant */
  977. X    /*  else
  978. X        s = s */        /* *s is new max */
  979. X    }
  980. X    else
  981. X        sprintf(t,"%ld,",(long)artnum);    /* put the number and comma */
  982. X    }
  983. X    else
  984. X    sprintf(t,"%ld",(long)artnum);    /* put the number there (wherever) */
  985. X    strcat(t,s);            /* copy remainder of line */
  986. X#ifdef DEBUGGING
  987. X    if (debug & DEB_XREF_MARKER) {
  988. X    printf("%s\n",mbuf) FLUSH;
  989. X    }
  990. X#endif
  991. X    free(rcline[ngnum]);
  992. X    rcline[ngnum] = mbuf;        /* pull the switcheroo */
  993. X    *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  994. X                    /* wipe out : or ! */
  995. X    if (toread[ngnum] > TR_NONE)    /* lest we turn unsub into bogus */
  996. X    --toread[ngnum];
  997. X    return 0;
  998. X}
  999. X
  1000. X#ifdef MCHASE
  1001. X/* delete an article number from a newsgroup, if it is there */
  1002. X
  1003. void
  1004. subartnum(artnum,ngnam)
  1005. register ART_NUM artnum;
  1006. char *ngnam;
  1007. X{
  1008. X    register NG_NUM ngnum = find_ng(ngnam);
  1009. X    register char *s, *t;
  1010. X    register ART_NUM min, max;
  1011. X    char *mbuf;
  1012. X    int curlen;
  1013. X
  1014. X    if (!artnum)
  1015. X    return;
  1016. X    if (ngnum == nextrcline || !rcnums[ngnum])
  1017. X    return;                /* not found in newsrc? */
  1018. X#ifdef DEBUGGING
  1019. X    if (debug & DEB_XREF_MARKER) {
  1020. X    printf("%ld<-\n%s%c%s\n",(long)artnum,rcline[ngnum],rcchar[ngnum],
  1021. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1022. X    }
  1023. X#endif
  1024. X    s = rcline[ngnum] + rcnums[ngnum];
  1025. X    while (*s == ' ') s++;        /* skip spaces */
  1026. X    
  1027. X    /* a little optimization, since it is almost always the last number */
  1028. X    
  1029. X    for (t=s; *t; t++) ;        /* find end of string */
  1030. X    curlen = t-rcline[ngnum];
  1031. X    for (t--; isdigit(*t); t--) ;    /* find previous delim */
  1032. X    if (*t == ',' && atol(t+1) == artnum) {
  1033. X    *t = '\0';
  1034. X    if (toread[ngnum] >= TR_NONE)
  1035. X        ++toread[ngnum];
  1036. X#ifdef DEBUGGING
  1037. X    if (debug & DEB_XREF_MARKER)
  1038. X        printf("%s%c %s\n",rcline[ngnum],rcchar[ngnum],s) FLUSH;
  1039. X#endif
  1040. X    return;
  1041. X    }
  1042. X
  1043. X    /* not the last number, oh well, we may need the length anyway */
  1044. X
  1045. X    while (isdigit(*s) && artnum >= (min = atol(s))) {
  1046. X                    /* while it might have been read */
  1047. X    for (t = s; isdigit(*t); t++) ;    /* skip number */
  1048. X    if (*t == '-') {        /* is it a range? */
  1049. X        t++;            /* skip to next number */
  1050. X        max = atol(t);
  1051. X        while (isdigit(*t)) t++;    /* skip second number */
  1052. X        if (artnum <= max) {
  1053. X                    /* it is in range => already read */
  1054. X        if (artnum == min) {
  1055. X            min++;
  1056. X            artnum = 0;
  1057. X        }
  1058. X        else if (artnum == max) {
  1059. X            max--;
  1060. X            artnum = 0;
  1061. X        }
  1062. X#ifdef USETHREADS
  1063. X        *(rcline[ngnum] + rcnums[ngnum] - 1) = RCCHAR(rcchar[ngnum]);
  1064. X#else
  1065. X        *(rcline[ngnum] + rcnums[ngnum] - 1) = rcchar[ngnum];
  1066. X#endif
  1067. X        mbuf = safemalloc((MEM_SIZE)(curlen + (artnum?15:2)));
  1068. X        *s = '\0';
  1069. X        strcpy(mbuf,rcline[ngnum]);    /* make new rc line */
  1070. X        s = mbuf + (s-rcline[ngnum]);
  1071. X                    /* point s into mbuf now */
  1072. X        if (artnum) {        /* split into two ranges? */
  1073. X            prange(s,min,artnum-1);
  1074. X            s += strlen(s);
  1075. X            *s++ = ',';
  1076. X            prange(s,artnum+1,max);
  1077. X        }
  1078. X        else            /* only one range */
  1079. X            prange(s,min,max);
  1080. X        s += strlen(s);
  1081. X        strcpy(s,t);        /* copy remainder over */
  1082. X#ifdef DEBUGGING
  1083. X        if (debug & DEB_XREF_MARKER) {
  1084. X            printf("%s\n",mbuf) FLUSH;
  1085. X        }
  1086. X#endif
  1087. X        free(rcline[ngnum]);
  1088. X        rcline[ngnum] = mbuf;    /* pull the switcheroo */
  1089. X        *(rcline[ngnum] + rcnums[ngnum] - 1) = '\0';
  1090. X                    /* wipe out : or ! */
  1091. X        if (toread[ngnum] >= TR_NONE)
  1092. X            ++toread[ngnum];
  1093. X        return;
  1094. X        }
  1095. X    }
  1096. X    else {
  1097. X        if (artnum == min) {    /* explicitly a read article? */
  1098. X        if (*t == ',')        /* pick a comma, any comma */
  1099. X            t++;
  1100. X        else if (s[-1] == ',')
  1101. X            s--;
  1102. X        else if (s[-2] == ',')    /* (in case of space) */
  1103. X            s -= 2;
  1104. X        strcpy(s,t);        /* no need to realloc */
  1105. X        if (toread[ngnum] >= TR_NONE)
  1106. X            ++toread[ngnum];
  1107. X#ifdef DEBUGGING
  1108. X        if (debug & DEB_XREF_MARKER) {
  1109. X            printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  1110. X              rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1111. X        }
  1112. X#endif
  1113. X        return;
  1114. X        }
  1115. X    }
  1116. X    while (*t && !isdigit(*t)) t++;    /* skip comma and any spaces */
  1117. X    s = t;
  1118. X    }
  1119. X}
  1120. X
  1121. void
  1122. prange(where,min,max)
  1123. char *where;
  1124. ART_NUM min,max;
  1125. X{
  1126. X    if (min == max)
  1127. X    sprintf(where,"%ld",(long)min);
  1128. X    else
  1129. X    sprintf(where,"%ld-%ld",(long)min,(long)max);
  1130. X}
  1131. X#endif
  1132. X
  1133. X/* calculate the number of unread articles for a newsgroup */
  1134. X
  1135. void
  1136. set_toread(ngnum)
  1137. register NG_NUM ngnum;
  1138. X{
  1139. X    register char *s, *c, *h;
  1140. X    char tmpbuf[64], *mybuf = tmpbuf;
  1141. X    char *nums;
  1142. X    int length;
  1143. X#ifdef CACHEFIRST
  1144. X    bool virgin_ng = (!abs1st[ngnum]);
  1145. X#endif
  1146. X    ART_NUM ngsize = getngsize(ngnum);
  1147. X    ART_NUM unread = ngsize;
  1148. X    ART_NUM newmax;
  1149. X
  1150. X#if defined(DEBUGGING) || defined(USETHREADS)
  1151. X    ngmax[ngnum] = ngsize;        /* for checking out-of-range Xrefs */
  1152. X#endif
  1153. X    if (ngsize == TR_BOGUS) {
  1154. X    printf("\nWarning!  Bogus newsgroup: %s\n",rcline[ngnum]) FLUSH;
  1155. X    paranoid = TRUE;
  1156. X    toread[ngnum] = TR_BOGUS;
  1157. X    return;
  1158. X    }
  1159. X#ifdef CACHEFIRST
  1160. X    if (virgin_ng)
  1161. X#else
  1162. X    if (!toread[ngnum])
  1163. X#endif
  1164. X    {
  1165. X    sprintf(tmpbuf," 1-%ld",(long)ngsize);
  1166. X    if (strNE(tmpbuf,rcline[ngnum]+rcnums[ngnum]))
  1167. X        checkexpired(ngnum,ngsize);    /* this might realloc rcline */
  1168. X    }
  1169. X    nums = rcline[ngnum]+rcnums[ngnum];
  1170. X    length = strlen(nums);
  1171. X    if (length >= 60)
  1172. X    mybuf = safemalloc((MEM_SIZE)(length+5));
  1173. X    strcpy(mybuf,nums);
  1174. X    mybuf[length++] = ',';
  1175. X    mybuf[length] = '\0';
  1176. X    for (s = mybuf; isspace(*s); s++)
  1177. X        ;
  1178. X    for ( ; (c = index(s,',')) != Nullch ; s = ++c) {
  1179. X                    /* for each range */
  1180. X    *c = '\0';            /* keep index from running off */
  1181. X    if ((h = index(s,'-')) != Nullch)    /* find - in range, if any */
  1182. X        unread -= (newmax = atol(h+1)) - atol(s) + 1;
  1183. X    else if (newmax = atol(s))
  1184. X        unread--;        /* recalculate length */
  1185. X    if (newmax > ngsize) {    /* paranoia check */
  1186. X        unread = -1;
  1187. X        break;
  1188. X    }
  1189. X    }
  1190. X    if (unread >= 0)        /* reasonable number? */
  1191. X    toread[ngnum] = (ART_UNREAD)unread;
  1192. X                    /* remember how many are left */
  1193. X    else {                /* SOMEONE RESET THE NEWSGROUP!!! */
  1194. X    toread[ngnum] = (ART_UNREAD)ngsize;
  1195. X                    /* assume nothing carried over */
  1196. X    printf("\nWarning!  Somebody reset %s--assuming nothing read.\n",
  1197. X        rcline[ngnum]) FLUSH;
  1198. X    *(rcline[ngnum] + rcnums[ngnum]) = '\0';
  1199. X    paranoid = TRUE;        /* enough to make a guy paranoid */
  1200. X    }
  1201. X    if (mybuf != tmpbuf)
  1202. X    free(mybuf);
  1203. X    if (rcchar[ngnum] == NEGCHAR)
  1204. X    toread[ngnum] = TR_UNSUB;
  1205. X}
  1206. X
  1207. X/* make sure expired articles are marked as read */
  1208. X
  1209. void
  1210. checkexpired(ngnum,ngsize)
  1211. register NG_NUM ngnum;
  1212. ART_NUM ngsize;
  1213. X{
  1214. X    register ART_NUM a1st = getabsfirst(ngnum,ngsize);
  1215. X    register char *s, *t;
  1216. X    register ART_NUM num, lastnum = 0;
  1217. X    char *mbuf, *newnum;
  1218. X
  1219. X    if (a1st<=1)
  1220. X    return;
  1221. X#ifdef DEBUGGING
  1222. X    if (debug & DEB_XREF_MARKER) {
  1223. X    printf("1-%ld->\n%s%c%s\n",(long)(a1st-1),rcline[ngnum],rcchar[ngnum],
  1224. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1225. X    }
  1226. X#endif
  1227. X    for (s = rcline[ngnum] + rcnums[ngnum]; isspace(*s); s++);
  1228. X    while (*s && (num = atol(s)) <= a1st) {
  1229. X    while (isdigit(*s)) s++;
  1230. X    while (*s && !isdigit(*s)) s++;
  1231. X    lastnum = num;
  1232. X    }
  1233. X    if (*s) {
  1234. X    if (s[-1] == '-') {            /* landed in a range? */
  1235. X        if (lastnum != 1) {
  1236. X        if (3 + strlen(s) > strlen(rcline[ngnum]+rcnums[ngnum])) {
  1237. X            mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + 3 +
  1238. X            strlen(s) + 1));
  1239. X            strcpy(mbuf, rcline[ngnum]);
  1240. X            sprintf(mbuf+rcnums[ngnum]," 1-%s",s);
  1241. X            free(rcline[ngnum]);
  1242. X            rcline[ngnum] = mbuf;
  1243. X        } else {
  1244. X            sprintf(rcline[ngnum]+rcnums[ngnum]," 1-%s",s);
  1245. X        }
  1246. X        }
  1247. X        goto ret;
  1248. X    }
  1249. X    }
  1250. X    /* s now points to what should follow first range */
  1251. X    if (s - rcline[ngnum] > rcnums[ngnum] + 10) 
  1252. X    mbuf = rcline[ngnum];
  1253. X    else {
  1254. X    mbuf = safemalloc((MEM_SIZE)(rcnums[ngnum] + strlen(s) + 10));
  1255. X    strcpy(mbuf,rcline[ngnum]);
  1256. X    }
  1257. X    newnum = t = mbuf+rcnums[ngnum];
  1258. X    sprintf(t," 1-%ld",(long)(a1st - (lastnum != a1st)));
  1259. X    if (*s) {
  1260. X    t += strlen(t);
  1261. X    *t++ = ',';
  1262. X    strcpy(t,s);
  1263. X    }
  1264. X    if (!checkflag && mbuf == rcline[ngnum]) {
  1265. X    rcline[ngnum] = saferealloc(rcline[ngnum],
  1266. X        (MEM_SIZE)(rcnums[ngnum] + strlen(newnum) + 1));
  1267. X    }
  1268. X    else {
  1269. X    if (!checkflag)
  1270. X        free(rcline[ngnum]);
  1271. X    rcline[ngnum] = mbuf;
  1272. X    }
  1273. X
  1274. ret:;        /* semicolon in case DEBUGGING undefined */
  1275. X#ifdef DEBUGGING
  1276. X    if (debug & DEB_XREF_MARKER) {
  1277. X    printf("%s%c%s\n",rcline[ngnum],rcchar[ngnum],
  1278. X      rcline[ngnum] + rcnums[ngnum]) FLUSH;
  1279. X    }
  1280. X#endif
  1281. X}
  1282. X
  1283. END_OF_FILE
  1284. if test 13041 -ne `wc -c <'rcln.c'`; then
  1285.     echo shar: \"'rcln.c'\" unpacked with wrong size!
  1286. fi
  1287. # end of 'rcln.c'
  1288. fi
  1289. if test -f 'search.c' -a "${1}" != "-c" ; then 
  1290.   echo shar: Will not clobber existing file \"'search.c'\"
  1291. else
  1292. echo shar: Extracting \"'search.c'\" \(13210 characters\)
  1293. sed "s/^X//" >'search.c' <<'END_OF_FILE'
  1294. X/* $Id: search.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
  1295. X *
  1296. X * $Log: search.c,v $
  1297. X * Revision 4.4  1991/09/09  20:27:37  sob
  1298. X * release 4.4
  1299. X *
  1300. X *
  1301. X */
  1302. X
  1303. X/* string search routines */
  1304. X/*        Copyright (c) 1981,1980 James Gosling        */
  1305. X/* Modified Aug. 12, 1981 by Tom London to include regular expressions
  1306. X   as in ed.  RE stuff hacked over by jag to correct a few major problems,
  1307. X   mainly dealing with searching within the buffer rather than copying
  1308. X   each line to a separate array.  Newlines can now appear in RE's */
  1309. X
  1310. X/* Ripped to shreds and glued back together to make a search package,
  1311. X * July 6, 1984, by Larry Wall. (If it doesn't work, it's probably my fault.)
  1312. X * Changes include:
  1313. X *    Buffer, window, and mlisp stuff gone.
  1314. X *    Translation tables reduced to 1 table.
  1315. X *    Expression buffer is now dynamically allocated.
  1316. X *    Character classes now implemented with a bitmap.
  1317. X */
  1318. X
  1319. X#include "EXTERN.h"
  1320. X#include "common.h"
  1321. X#include "util.h"
  1322. X#include "INTERN.h"
  1323. X#include "search.h"
  1324. X
  1325. X#ifndef BITSPERBYTE
  1326. X#define BITSPERBYTE 8
  1327. X#endif
  1328. X
  1329. X#define BMAPSIZ (127 / BITSPERBYTE + 1)
  1330. X
  1331. X/* meta characters in the "compiled" form of a regular expression */
  1332. X#define    CBRA    2        /* \( -- begin bracket */
  1333. X#define    CCHR    4        /* a vanilla character */
  1334. X#define    CDOT    6        /* . -- match anything except a newline */
  1335. X#define    CCL    8        /* [...] -- character class */
  1336. X#define    NCCL    10        /* [^...] -- negated character class */
  1337. X#define    CDOL    12        /* $ -- matches the end of a line */
  1338. X#define    CEND    14        /* The end of the pattern */
  1339. X#define    CKET    16        /* \) -- close bracket */
  1340. X#define    CBACK    18        /* \N -- backreference to the Nth bracketed
  1341. X                   string */
  1342. X#define CIRC    20        /* ^ matches the beginning of a line */
  1343. X
  1344. X#define WORD    32        /* matches word character \w */
  1345. X#define NWORD    34        /* matches non-word characer \W */
  1346. X#define WBOUND    36        /* matches word boundary \b */
  1347. X#define NWBOUND    38        /* matches non-(word boundary) \B */
  1348. X#define    STAR    01        /* * -- Kleene star, repeats the previous
  1349. X                   REas many times as possible; the value
  1350. X                   ORs with the other operator types */
  1351. X#define ASCSIZ 0200
  1352. typedef char    TRANSTABLE[ASCSIZ];
  1353. X
  1354. static    TRANSTABLE trans = {
  1355. X0000,0001,0002,0003,0004,0005,0006,0007,
  1356. X0010,0011,0012,0013,0014,0015,0016,0017,
  1357. X0020,0021,0022,0023,0024,0025,0026,0027,
  1358. X0030,0031,0032,0033,0034,0035,0036,0037,
  1359. X0040,0041,0042,0043,0044,0045,0046,0047,
  1360. X0050,0051,0052,0053,0054,0055,0056,0057,
  1361. X0060,0061,0062,0063,0064,0065,0066,0067,
  1362. X0070,0071,0072,0073,0074,0075,0076,0077,
  1363. X0100,0101,0102,0103,0104,0105,0106,0107,
  1364. X0110,0111,0112,0113,0114,0115,0116,0117,
  1365. X0120,0121,0122,0123,0124,0125,0126,0127,
  1366. X0130,0131,0132,0133,0134,0135,0136,0137,
  1367. X0140,0141,0142,0143,0144,0145,0146,0147,
  1368. X0150,0151,0152,0153,0154,0155,0156,0157,
  1369. X0160,0161,0162,0163,0164,0165,0166,0167,
  1370. X0170,0171,0172,0173,0174,0175,0176,0177,
  1371. X};
  1372. static bool folding = FALSE;
  1373. X
  1374. static int err;
  1375. static char *FirstCharacter;
  1376. X
  1377. void
  1378. search_init()
  1379. X{
  1380. X#ifdef UNDEF
  1381. X    register int    i;
  1382. X    
  1383. X    for (i = 0; i < ASCSIZ; i++)
  1384. X    trans[i] = i;
  1385. X#else
  1386. X    ;
  1387. X#endif
  1388. X}
  1389. X
  1390. void
  1391. init_compex(compex)
  1392. register COMPEX *compex;
  1393. X{
  1394. X    /* the following must start off zeroed */
  1395. X
  1396. X    compex->eblen = 0;
  1397. X    compex->brastr = Nullch;
  1398. X}
  1399. X
  1400. void
  1401. free_compex(compex)
  1402. register COMPEX *compex;
  1403. X{
  1404. X    if (compex->eblen) {
  1405. X    free(compex->expbuf);
  1406. X    compex->eblen = 0;
  1407. X    }
  1408. X    if (compex->brastr) {
  1409. X    free(compex->brastr);
  1410. X    compex->brastr = Nullch;
  1411. X    }
  1412. X}
  1413. X
  1414. static char *gbr_str = Nullch;
  1415. static int gbr_siz = 0;
  1416. X
  1417. char *
  1418. getbracket(compex,n)
  1419. register COMPEX *compex;
  1420. int n;
  1421. X{
  1422. X    int length = compex->braelist[n] - compex->braslist[n];
  1423. X
  1424. X    if (!compex->nbra || n > compex->nbra || !compex->braelist[n] || length<0)
  1425. X    return nullstr;
  1426. X    growstr(&gbr_str, &gbr_siz, length+1);
  1427. X    safecpy(gbr_str, compex->braslist[n], length+1);
  1428. X    return gbr_str;
  1429. X}
  1430. X
  1431. void
  1432. case_fold(which)
  1433. int which;
  1434. X{
  1435. X    register int i;
  1436. X
  1437. X    if (which != folding) {
  1438. X    if (which) {
  1439. X        for (i = 'A'; i <= 'Z'; i++)
  1440. X        trans[i] = tolower(i);
  1441. X    }
  1442. X    else {
  1443. X        for (i = 'A'; i <= 'Z'; i++)
  1444. X        trans[i] = i;
  1445. X    }
  1446. X    folding = which;
  1447. X    }
  1448. X}
  1449. X
  1450. X/* Compile the given regular expression into a [secret] internal format */
  1451. X
  1452. char *
  1453. compile (compex, strp, RE, fold)
  1454. register COMPEX *compex;
  1455. register char   *strp;
  1456. int RE;
  1457. int fold;
  1458. X{
  1459. X    register int c;
  1460. X    register char  *ep;
  1461. X    char   *lastep;
  1462. X    char    bracket[NBRA],
  1463. X       *bracketp;
  1464. X    char **alt = compex->alternatives;
  1465. X    char *retmes = "Badly formed search string";
  1466. X    case_fold(compex->do_folding = fold);
  1467. X    if (!compex->eblen) {
  1468. X    compex->expbuf = safemalloc(84);
  1469. X    compex->eblen = 80;
  1470. X    }
  1471. X    ep = compex->expbuf;        /* point at expression buffer */
  1472. X    *alt++ = ep;            /* first alternative starts here */
  1473. X    bracketp = bracket;            /* first bracket goes here */
  1474. X    if (*strp == 0) {            /* nothing to compile? */
  1475. X    if (*ep == 0)            /* nothing there yet? */
  1476. X        return "Null search string";
  1477. X    return Nullch;            /* just keep old expression */
  1478. X    }
  1479. X    compex->nbra = 0;            /* no brackets yet */
  1480. X    lastep = 0;
  1481. X    for (;;) {
  1482. X    if (ep - compex->expbuf >= compex->eblen)
  1483. X        grow_eb(compex);
  1484. X    c = *strp++;            /* fetch next char of pattern */
  1485. X    if (c == 0) {            /* end of pattern? */
  1486. X        if (bracketp != bracket) {    /* balanced brackets? */
  1487. X#ifdef VERBOSE
  1488. X        retmes = "Unbalanced parens";
  1489. X#endif
  1490. X        goto cerror;
  1491. X        }
  1492. X        *ep++ = CEND;        /* terminate expression */
  1493. X        *alt++ = 0;            /* terminal alternative list */
  1494. X        /*
  1495. X        compex->eblen = ep - compex->expbuf + 1;
  1496. X        compex->expbuf = saferealloc(compex->expbuf,compex->eblen+4); */
  1497. X        return Nullch;        /* return success */
  1498. X    }
  1499. X    if (c != '*')
  1500. X        lastep = ep;
  1501. X    if (!RE) {            /* just a normal search string? */
  1502. X        *ep++ = CCHR;        /* everything is a normal char */
  1503. X        *ep++ = c;
  1504. X    }
  1505. X    else                /* it is a regular expression */
  1506. X        switch (c) {
  1507. X        case '\\':        /* meta something */
  1508. X            switch (c = *strp++) {
  1509. X            case '(':
  1510. X            if (compex->nbra >= NBRA) {
  1511. X#ifdef VERBOSE
  1512. X                retmes = "Too many parens";
  1513. X#endif
  1514. X                goto cerror;
  1515. X            }
  1516. X            *bracketp++ = ++compex->nbra;
  1517. X            *ep++ = CBRA;
  1518. X            *ep++ = compex->nbra;
  1519. X            break;
  1520. X            case '|':
  1521. X            if (bracketp>bracket) {
  1522. X#ifdef VERBOSE
  1523. X                retmes = "No \\| in parens";    /* Alas! */
  1524. X#endif
  1525. X                goto cerror;
  1526. X            }
  1527. X            *ep++ = CEND;
  1528. X            *alt++ = ep;
  1529. X            break;
  1530. X            case ')':
  1531. X            if (bracketp <= bracket) {
  1532. X#ifdef VERBOSE
  1533. X                retmes = "Unmatched right paren";
  1534. X#endif
  1535. X                goto cerror;
  1536. X            }
  1537. X            *ep++ = CKET;
  1538. X            *ep++ = *--bracketp;
  1539. X            break;
  1540. X            case 'w':
  1541. X            *ep++ = WORD;
  1542. X            break;
  1543. X            case 'W':
  1544. X            *ep++ = NWORD;
  1545. X            break;
  1546. X            case 'b':
  1547. X            *ep++ = WBOUND;
  1548. X            break;
  1549. X            case 'B':
  1550. X            *ep++ = NWBOUND;
  1551. X            break;
  1552. X            case '0': case '1': case '2': case '3': case '4':
  1553. X            case '5': case '6': case '7': case '8': case '9':
  1554. X            *ep++ = CBACK;
  1555. X            *ep++ = c - '0';
  1556. X            break;
  1557. X            default:
  1558. X            *ep++ = CCHR;
  1559. X            if (c == '\0')
  1560. X                goto cerror;
  1561. X            *ep++ = c;
  1562. X            break;
  1563. X            }
  1564. X            break;
  1565. X        case '.':
  1566. X            *ep++ = CDOT;
  1567. X            continue;
  1568. X        case '*':
  1569. X            if (lastep == 0 || *lastep == CBRA || *lastep == CKET
  1570. X            || *lastep == CIRC
  1571. X            || (*lastep&STAR)|| *lastep>NWORD)
  1572. X            goto defchar;
  1573. X            *lastep |= STAR;
  1574. X            continue;
  1575. X        case '^':
  1576. X            if (ep != compex->expbuf && ep[-1] != CEND)
  1577. X            goto defchar;
  1578. X            *ep++ = CIRC;
  1579. X            continue;
  1580. X        case '$':
  1581. X            if (*strp != 0 && (*strp != '\\' || strp[1] != '|'))
  1582. X            goto defchar;
  1583. X            *ep++ = CDOL;
  1584. X            continue;
  1585. X        case '[': {        /* character class */
  1586. X            register int i;
  1587. X            
  1588. X            if (ep - compex->expbuf >= compex->eblen - BMAPSIZ)
  1589. X            grow_eb(compex);    /* reserve bitmap */
  1590. X            for (i = BMAPSIZ; i; --i)
  1591. X            ep[i] = 0;
  1592. X            
  1593. X            if ((c = *strp++) == '^') {
  1594. X            c = *strp++;
  1595. X            *ep++ = NCCL;    /* negated */
  1596. X            }
  1597. X            else
  1598. X            *ep++ = CCL;    /* normal */
  1599. X            
  1600. X            i = 0;        /* remember oldchar */
  1601. X            do {
  1602. X            if (c == '\0') {
  1603. X#ifdef VERBOSE
  1604. X                retmes = "Missing ]";
  1605. X#endif
  1606. X                goto cerror;
  1607. X            }
  1608. X            if (*strp == '-' && *(++strp))
  1609. X                i = *strp++;
  1610. X            else
  1611. X                i = c;
  1612. X            while (c <= i) {
  1613. X                ep[c / BITSPERBYTE] |= 1 << (c % BITSPERBYTE);
  1614. X                if (fold && isalpha(c))
  1615. X                ep[(c ^ 32) / BITSPERBYTE] |=
  1616. X                    1 << ((c ^ 32) % BITSPERBYTE);
  1617. X                    /* set the other bit too */
  1618. X                c++;
  1619. X            }
  1620. X            } while ((c = *strp++) != ']');
  1621. X            ep += BMAPSIZ;
  1622. X            continue;
  1623. X        }
  1624. X        defchar:
  1625. X        default:
  1626. X            *ep++ = CCHR;
  1627. X            *ep++ = c;
  1628. X        }
  1629. X    }
  1630. cerror:
  1631. X    compex->expbuf[0] = 0;
  1632. X    compex->nbra = 0;
  1633. X    return retmes;
  1634. X}
  1635. X
  1636. void
  1637. grow_eb(compex)
  1638. register COMPEX *compex;
  1639. X{
  1640. X    compex->eblen += 80;
  1641. X    compex->expbuf = saferealloc(compex->expbuf, (MEM_SIZE)compex->eblen + 4);
  1642. X}
  1643. X
  1644. char *
  1645. execute (compex, addr)
  1646. register COMPEX *compex;
  1647. char *addr;
  1648. X{
  1649. X    register char *p1 = addr;
  1650. X    register char *trt = trans;
  1651. X    register int c;
  1652. X    if (addr == Nullch || compex->expbuf == Nullch)
  1653. X    return Nullch;
  1654. X    if (compex->nbra) {            /* any brackets? */
  1655. X    for (c = 0; c <= compex->nbra; c++)
  1656. X        compex->braslist[c] = compex->braelist[c] = Nullch;
  1657. X    if (compex->brastr)
  1658. X        free(compex->brastr);
  1659. X    compex->brastr = savestr(p1);    /* in case p1 is not static */
  1660. X    p1 = compex->brastr;        /* ! */
  1661. X    }
  1662. X    case_fold(compex->do_folding);    /* make sure table is correct */
  1663. X    FirstCharacter = p1;        /* for ^ tests */
  1664. X    if (compex->expbuf[0] == CCHR && !compex->alternatives[1]) {
  1665. X    c = trt[compex->expbuf[1]];    /* fast check for first character */
  1666. X    do {
  1667. X        if (trt[*p1] == c && advance (compex, p1, compex->expbuf))
  1668. X        return p1;
  1669. X        p1++;
  1670. X    } while (*p1 && !err);
  1671. X    return Nullch;
  1672. X    }
  1673. X    else {            /* regular algorithm */
  1674. X    do {
  1675. X        register char **alt = compex->alternatives;
  1676. X        while (*alt) {
  1677. X        if (advance (compex, p1, *alt++))
  1678. X            return p1;
  1679. X        }
  1680. X        p1++;
  1681. X    } while (*p1 && !err);
  1682. X    return Nullch;
  1683. X    }
  1684. X   /*NOTREACHED*/
  1685. X}
  1686. X/* advance the match of the regular expression starting at ep along the
  1687. X   string lp, simulates an NDFSA */
  1688. bool
  1689. advance (compex, lp, ep)
  1690. register COMPEX *compex;
  1691. register char *ep;
  1692. register char *lp;
  1693. X{
  1694. X    register char *curlp;
  1695. X    register char *trt = trans;
  1696. X    register int i;
  1697. X    while ((*ep & STAR) || *lp || *ep == CIRC || *ep == CKET)
  1698. X    switch (*ep++) {
  1699. X        case CCHR:
  1700. X        if (trt[*ep++] != trt[*lp]) return FALSE;
  1701. X        lp++;
  1702. X        continue;
  1703. X        case CDOT:
  1704. X        if (*lp == '\n') return FALSE;
  1705. X        lp++;
  1706. X        continue;
  1707. X        case CDOL:
  1708. X        if (!*lp || *lp == '\n')
  1709. X            continue;
  1710. X        return FALSE;
  1711. X        case CIRC:
  1712. X        if (lp == FirstCharacter || lp[-1]=='\n')
  1713. X            continue;
  1714. X        return FALSE;
  1715. X        case WORD:
  1716. X        if (isalnum(*lp)) {
  1717. X            lp++;
  1718. X            continue;
  1719. X        }
  1720. X        return FALSE;
  1721. X        case NWORD:
  1722. X        if (!isalnum(*lp)) {
  1723. X            lp++;
  1724. X            continue;
  1725. X        }
  1726. X        return FALSE;
  1727. X        case WBOUND:
  1728. X        if ((lp == FirstCharacter || !isalnum(lp[-1])) !=
  1729. X            (!*lp || !isalnum(*lp)) )
  1730. X            continue;
  1731. X        return FALSE;
  1732. X        case NWBOUND:
  1733. X        if ((lp == FirstCharacter || !isalnum(lp[-1])) ==
  1734. X            (!*lp || !isalnum(*lp)))
  1735. X            continue;
  1736. X        return FALSE;
  1737. X        case CEND:
  1738. X        return TRUE;
  1739. X        case CCL:
  1740. X        if (cclass (ep, *lp, 1)) {
  1741. X            ep += BMAPSIZ;
  1742. X            lp++;
  1743. X            continue;
  1744. X        }
  1745. X        return FALSE;
  1746. X        case NCCL:
  1747. X        if (cclass (ep, *lp, 0)) {
  1748. X            ep += BMAPSIZ;
  1749. X            lp++;
  1750. X            continue;
  1751. X        }
  1752. X        return FALSE;
  1753. X        case CBRA:
  1754. X        compex->braslist[*ep++] = lp;
  1755. X        continue;
  1756. X        case CKET:
  1757. X        i = *ep++;
  1758. X        compex->braelist[i] = lp;
  1759. X        compex->braelist[0] = lp;
  1760. X        compex->braslist[0] = compex->braslist[i];
  1761. X        continue;
  1762. X        case CBACK:
  1763. X        if (compex->braelist[i = *ep++] == 0) {
  1764. X            fputs("bad braces\n",stdout) FLUSH;
  1765. X            err = TRUE;
  1766. X            return FALSE;
  1767. X        }
  1768. X        if (backref (compex, i, lp)) {
  1769. X            lp += compex->braelist[i] - compex->braslist[i];
  1770. X            continue;
  1771. X        }
  1772. X        return FALSE;
  1773. X        case CBACK | STAR:
  1774. X        if (compex->braelist[i = *ep++] == 0) {
  1775. X            fputs("bad braces\n",stdout) FLUSH;
  1776. X            err = TRUE;
  1777. X            return FALSE;
  1778. X        }
  1779. X        curlp = lp;
  1780. X        while (backref (compex, i, lp)) {
  1781. X            lp += compex->braelist[i] - compex->braslist[i];
  1782. X        }
  1783. X        while (lp >= curlp) {
  1784. X            if (advance (compex, lp, ep))
  1785. X            return TRUE;
  1786. X            lp -= compex->braelist[i] - compex->braslist[i];
  1787. X        }
  1788. X        continue;
  1789. X        case CDOT | STAR:
  1790. X        curlp = lp;
  1791. X        while (*lp++ && lp[-1] != '\n');
  1792. X        goto star;
  1793. X        case WORD | STAR:
  1794. X        curlp = lp;
  1795. X        while (*lp++ && isalnum(lp[-1]));
  1796. X        goto star;
  1797. X        case NWORD | STAR:
  1798. X        curlp = lp;
  1799. X        while (*lp++ && !isalnum(lp[-1]));
  1800. X        goto star;
  1801. X        case CCHR | STAR:
  1802. X        curlp = lp;
  1803. X        while (*lp++ && trt[lp[-1]] == trt[*ep]);
  1804. X        ep++;
  1805. X        goto star;
  1806. X        case CCL | STAR:
  1807. X        case NCCL | STAR:
  1808. X        curlp = lp;
  1809. X        while (*lp++ && cclass (ep, lp[-1], ep[-1] == (CCL | STAR)));
  1810. X        ep += BMAPSIZ;
  1811. X        goto star;
  1812. X    star:
  1813. X        do {
  1814. X            lp--;
  1815. X            if (advance (compex, lp, ep))
  1816. X            return TRUE;
  1817. X        } while (lp > curlp);
  1818. X        return FALSE;
  1819. X        default:
  1820. X        fputs("Badly compiled pattern\n",stdout) FLUSH;
  1821. X        err = TRUE;
  1822. X        return -1;
  1823. X    }
  1824. X    if (*ep == CEND || *ep == CDOL) {
  1825. X        return TRUE;
  1826. X    }
  1827. X    return FALSE;
  1828. X}
  1829. bool
  1830. backref (compex, i, lp)
  1831. register COMPEX *compex;
  1832. register int i;
  1833. register char *lp;
  1834. X{
  1835. X    register char *bp;
  1836. X    bp = compex->braslist[i];
  1837. X    while (*lp && *bp == *lp) {
  1838. X    bp++;
  1839. X    lp++;
  1840. X    if (bp >= compex->braelist[i])
  1841. X        return TRUE;
  1842. X    }
  1843. X    return FALSE;
  1844. X}
  1845. X
  1846. bool
  1847. cclass (set, c, af)
  1848. register char  *set;
  1849. register int c;
  1850. int af;
  1851. X{
  1852. X    c &= 0177;
  1853. X#if BITSPERBYTE == 8
  1854. X    if (set[c >> 3] & 1 << (c & 7))
  1855. X#else
  1856. X    if (set[c / BITSPERBYTE] & 1 << (c % BITSPERBYTE))
  1857. X#endif
  1858. X    return af;
  1859. X    return !af;
  1860. X}
  1861. END_OF_FILE
  1862. if test 13210 -ne `wc -c <'search.c'`; then
  1863.     echo shar: \"'search.c'\" unpacked with wrong size!
  1864. fi
  1865. # end of 'search.c'
  1866. fi
  1867. if test -f 'sw.c' -a "${1}" != "-c" ; then 
  1868.   echo shar: Will not clobber existing file \"'sw.c'\"
  1869. else
  1870. echo shar: Extracting \"'sw.c'\" \(12012 characters\)
  1871. sed "s/^X//" >'sw.c' <<'END_OF_FILE'
  1872. X/* $Id: sw.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
  1873. X *
  1874. X * $Log: sw.c,v $
  1875. X * Revision 4.4  1991/09/09  20:27:37  sob
  1876. X * release 4.4
  1877. X *
  1878. X *
  1879. X * 
  1880. X */
  1881. X/* This software is Copyright 1991 by Stan Barber. 
  1882. X *
  1883. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  1884. X * use this software as long as: there is no monetary profit gained
  1885. X * specifically from the use or reproduction of this software, it is not
  1886. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  1887. X * included prominently in any copy made. 
  1888. X *
  1889. X * The author make no claims as to the fitness or correctness of this software
  1890. X * for any use whatsoever, and it is provided as is. Any use of this software
  1891. X * is at the user's own risk. 
  1892. X */
  1893. X
  1894. X#include "EXTERN.h"
  1895. X#include "common.h"
  1896. X#include "util.h"
  1897. X#include "head.h"
  1898. X#include "only.h"
  1899. X#include "term.h"
  1900. X#include "ng.h"
  1901. X#include "intrp.h"
  1902. X#include "INTERN.h"
  1903. X#include "sw.h"
  1904. X
  1905. void
  1906. sw_init(argc,argv,tcbufptr)
  1907. int argc;
  1908. char *argv[];
  1909. char **tcbufptr;
  1910. X{
  1911. X    register int i;
  1912. X
  1913. X    if (argc >= 2 && strEQ(argv[1],"-c"))
  1914. X    checkflag=TRUE;            /* so we can optimize for -c */
  1915. X    interp(*tcbufptr,1024,GLOBINIT);
  1916. X    sw_file(tcbufptr,FALSE);
  1917. X#ifdef USETHREADS
  1918. X    if (use_threads)
  1919. X    safecpy(*tcbufptr,getval("TRNINIT",getenv("RNINIT")),1024);
  1920. X    else
  1921. X#endif
  1922. X    safecpy(*tcbufptr,getenv("RNINIT"),1024);
  1923. X    if (**tcbufptr) {
  1924. X    if (**tcbufptr == '/') {
  1925. X        sw_file(tcbufptr,TRUE);
  1926. X    }
  1927. X    else
  1928. X        sw_list(*tcbufptr);
  1929. X    }
  1930. X
  1931. X    for (i = 1; i < argc; i++)
  1932. X    decode_switch(argv[i]);
  1933. X}
  1934. X
  1935. void
  1936. sw_file(tcbufptr,bleat)
  1937. char **tcbufptr;
  1938. bool_int bleat;
  1939. X{
  1940. X    int initfd = open(*tcbufptr,0);
  1941. X    
  1942. X    if (initfd >= 0) {
  1943. X    fstat(initfd,&filestat);
  1944. X    if (filestat.st_size > 1024)
  1945. X        *tcbufptr = saferealloc(*tcbufptr,(MEM_SIZE)filestat.st_size);
  1946. X    if (filestat.st_size) {
  1947. X        read(initfd,*tcbufptr,(int)filestat.st_size);
  1948. X        (*tcbufptr)[filestat.st_size-1] = '\0';
  1949. X                /* wipe out last newline */
  1950. X        sw_list(*tcbufptr);
  1951. X    }
  1952. X    else
  1953. X        **tcbufptr = '\0';
  1954. X    close(initfd);
  1955. X    }
  1956. X    else {
  1957. X    if (bleat)
  1958. X        printf(cantopen,*tcbufptr) FLUSH;
  1959. X    **tcbufptr = '\0';
  1960. X    }
  1961. X}
  1962. X
  1963. X/* decode a list of space separated switches */
  1964. X
  1965. void
  1966. sw_list(swlist)
  1967. char *swlist;
  1968. X{
  1969. X    char *tmplist = safemalloc((MEM_SIZE) strlen(swlist) + 2);
  1970. X                    /* semi-automatic string */
  1971. X    register char *p, inquote = 0;
  1972. X
  1973. X    strcpy(tmplist,swlist);
  1974. X    for (p=tmplist; isspace(*p); p++) ;    /* skip any initial spaces */
  1975. X    while (*p) {            /* "String, or nothing" */
  1976. X    if (!inquote && isspace(*p)) {    /* word delimiter? */
  1977. X        *p++ = '\0';        /* chop here */
  1978. X        while (isspace(*p))        /* these will be ignored later */
  1979. X        p++;
  1980. X    }
  1981. X    else if (inquote == *p) {
  1982. X        strcpy(p,p+1);        /* delete trailing quote */
  1983. X        inquote = 0;        /* no longer quoting */
  1984. X    }
  1985. X    else if (!inquote && *p == '"' || *p == '\'') {
  1986. X                    /* OK, I know when I am not wanted */
  1987. X        inquote = *p;        /* remember single or double */
  1988. X        strcpy(p,p+1);        /* delete the quote */
  1989. X    }                /* (crude, but effective) */
  1990. X    else if (*p == '\\') {        /* quoted something? */
  1991. X        if (p[1] == '\n')        /* newline? */
  1992. X        strcpy(p,p+2);        /* "I didn't see anything" */
  1993. X        else {
  1994. X        strcpy(p,p+1);        /* delete the backwhack */
  1995. X        p++;            /* leave the whatever alone */
  1996. X        }
  1997. X    }
  1998. X    else
  1999. X        p++;            /* normal char, leave it alone */
  2000. X    }
  2001. X    *++p = '\0';            /* put an extra null on the end */
  2002. X    if (inquote)
  2003. X    printf("Unmatched %c in switch\n",inquote) FLUSH;
  2004. X    for (p = tmplist; *p; /* p += strlen(p)+1 */ ) {
  2005. X    decode_switch(p);
  2006. X    while (*p++) ;            /* point at null + 1 */
  2007. X    }
  2008. X    free(tmplist);            /* this oughta be in Ada */
  2009. X}
  2010. X
  2011. X/* decode a single switch */
  2012. X
  2013. void
  2014. decode_switch(s)
  2015. register char *s;
  2016. X{
  2017. X    while (isspace(*s))            /* ignore leading spaces */
  2018. X    s++;
  2019. X#ifdef DEBUGGING
  2020. X    if (debug)
  2021. X    printf("Switch: %s\n",s) FLUSH;
  2022. X#endif
  2023. X    if (*s != '-' && *s != '+') {    /* newsgroup pattern */
  2024. X    setngtodo(s);
  2025. X    }
  2026. X    else {                /* normal switch */
  2027. X    bool upordown = *s == '-' ? TRUE : FALSE;
  2028. X    char tmpbuf[LBUFLEN];
  2029. X
  2030. X    s++;
  2031. X    switch (*s) {
  2032. X#ifdef TERMMOD
  2033. X    case '=': {
  2034. X        char *beg = s+1;
  2035. X
  2036. X        while (*s && *s != '-' && *s != '+') s++;
  2037. X        cpytill(tmpbuf,beg,*s);
  2038. X        if (upordown ? strEQ(getenv("TERM"),tmpbuf)
  2039. X                 : strNE(getenv("TERM"),tmpbuf) ) {
  2040. X        decode_switch(s);
  2041. X        }
  2042. X        break;
  2043. X    }
  2044. X#endif
  2045. X#ifdef BAUDMOD
  2046. X    case '0': case '1': case '2': case '3': case '4':
  2047. X    case '5': case '6': case '7': case '8': case '9':
  2048. X        if (upordown ? (just_a_sec*10 <= atoi(s))
  2049. X                 : (just_a_sec*10 >= atoi(s)) ) {
  2050. X        while (isdigit(*s)) s++;
  2051. X        decode_switch(s);
  2052. X        }
  2053. X        break;
  2054. X#endif
  2055. X    case '/':
  2056. X        if (checkflag)
  2057. X        break;
  2058. X#ifdef SETENV
  2059. X        setenv("SAVEDIR",  upordown ? "%p/%c" : "%p" );
  2060. X        setenv("SAVENAME", upordown ? "%a"    : "%^C");
  2061. X#else
  2062. X        notincl("-/");
  2063. X#endif
  2064. X        break;
  2065. X    case 'a':
  2066. X#ifdef USETHREADS
  2067. X        thread_always = upordown;
  2068. X#else
  2069. X        notincl("-a");
  2070. X#endif
  2071. X        break;
  2072. X    case 'c':
  2073. X        checkflag = upordown;
  2074. X        break;
  2075. X    case 'C':
  2076. X        s++;
  2077. X        if (*s == '=') s++;
  2078. X        docheckwhen = atoi(s);
  2079. X        break;
  2080. X    case 'd': {
  2081. X        if (checkflag)
  2082. X        break;
  2083. X        s++;
  2084. X        if (*s == '=') s++;
  2085. X        if (cwd) {
  2086. X        chdir(cwd);
  2087. X        free(cwd);
  2088. X        }
  2089. X        cwd = savestr(s);
  2090. X        break;
  2091. X    }
  2092. X#ifdef DEBUGGING
  2093. X    case 'D':
  2094. X        s++;
  2095. X        if (*s == '=') s++;
  2096. X        if (*s)
  2097. X        if (upordown)
  2098. X            debug |= atoi(s);
  2099. X        else
  2100. X            debug &= ~atoi(s);
  2101. X        else
  2102. X        if (upordown)
  2103. X            debug |= 1;
  2104. X        else
  2105. X            debug = 0;
  2106. X        break;
  2107. X#endif
  2108. X    case 'e':
  2109. X        erase_screen = upordown;
  2110. X        break;
  2111. X    case 'E':
  2112. X#ifdef SETENV
  2113. X        s++;
  2114. X        if (*s == '=')
  2115. X        s++;
  2116. X        strcpy(tmpbuf,s);
  2117. X        s = index(tmpbuf,'=');
  2118. X        if (s) {
  2119. X        *s++ = '\0';
  2120. X        setenv(tmpbuf,s);
  2121. X        }
  2122. X        else
  2123. X        setenv(tmpbuf,nullstr);
  2124. X#else
  2125. X        notincl("-E");
  2126. X#endif
  2127. X        break;
  2128. X    case 'F':
  2129. X        s++;
  2130. X        indstr = savestr(s);
  2131. X        break;
  2132. X#ifdef INNERSEARCH
  2133. X    case 'g':
  2134. X        gline = atoi(s+1)-1;
  2135. X        break;
  2136. X#endif
  2137. X    case 'H':
  2138. X    case 'h': {
  2139. X        register int len, i;
  2140. X        char *t;
  2141. X        int flag = (*s == 'h' ? HT_HIDE : HT_MAGIC);
  2142. X        
  2143. X        if (checkflag)
  2144. X        break;
  2145. X        s++;
  2146. X        len = strlen(s);
  2147. X        for (t=s; *t; t++)
  2148. X        if (isupper(*t))
  2149. X           *t = tolower(*t);
  2150. X        for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  2151. X        if (!len || strnEQ(s,htype[i].ht_name,len))
  2152. X            if (upordown)
  2153. X            htype[i].ht_flags |= flag;
  2154. X            else
  2155. X            htype[i].ht_flags &= ~flag;
  2156. X        break;
  2157. X    }
  2158. X    case 'i':
  2159. X        s++;
  2160. X        if (*s == '=') s++;
  2161. X        initlines = atoi(s);
  2162. X        initlines_specified = TRUE;
  2163. X        break;
  2164. X    case 'l':
  2165. X        muck_up_clear = upordown;
  2166. X        break;
  2167. X    case 'L':
  2168. X#ifdef CLEAREOL
  2169. X        can_home_clear = upordown;
  2170. X#else
  2171. X        notincl("-L");
  2172. X#endif
  2173. X        break;
  2174. X    case 'M':
  2175. X        mbox_always = upordown;
  2176. X        break;
  2177. X    case 'm':
  2178. X        s++;
  2179. X        if (*s == '=') s++;
  2180. X        if (!upordown)
  2181. X        marking = NOMARKING;
  2182. X        else if (*s == 'u')
  2183. X        marking = UNDERLINE;
  2184. X        else {
  2185. X        marking = STANDOUT;
  2186. X        }
  2187. X        break;
  2188. X    case 'N':
  2189. X        norm_always = upordown;
  2190. X        break;
  2191. X#ifdef VERBOSE
  2192. X    case 'n':
  2193. X        fputs("This isn't readnews.  Don't use -n.\n\n",stdout) FLUSH;
  2194. X        break;
  2195. X#endif
  2196. X    case 'o':
  2197. X        s++;
  2198. X        if (*s == '=') s++;
  2199. X        if (*s <= '9' && *s >= '0') {
  2200. X        olden_days = atoi(s);
  2201. X        do {
  2202. X            s++;
  2203. X        } while (*s <= '9' && *s >= '0');
  2204. X        } else
  2205. X        olden_days = upordown;
  2206. X        break;
  2207. X    case 'r':
  2208. X        findlast = upordown;
  2209. X        break;
  2210. X    case 's':
  2211. X        s++;
  2212. X        if (*s == '=') s++;
  2213. X        if (*s) {
  2214. X        countdown = atoi(s);
  2215. X        suppress_cn = FALSE;
  2216. X        }
  2217. X        else {
  2218. X        if (!upordown)
  2219. X            countdown = 5;
  2220. X        suppress_cn = upordown;
  2221. X        }
  2222. X        break;
  2223. X    case 'S':
  2224. X#ifdef ARTSEARCH
  2225. X        s++;
  2226. X        if (*s == '=') s++;
  2227. X        if (*s)
  2228. X        scanon = atoi(s);
  2229. X        else
  2230. X        scanon = upordown*3;
  2231. X#else
  2232. X        notincl("-S");
  2233. X#endif
  2234. X        break;
  2235. X    case 't':
  2236. X#ifdef VERBOSE
  2237. X#ifdef TERSE
  2238. X        verbose = !upordown;
  2239. X#else
  2240. X        notincl("+t");
  2241. X#endif
  2242. X#else
  2243. X        notincl("+t");
  2244. X#endif
  2245. X        break;
  2246. X    case 'T':
  2247. X        typeahead = upordown;
  2248. X        break;
  2249. X    case 'v':
  2250. X#ifdef VERIFY
  2251. X        verify = upordown;
  2252. X#else
  2253. X        notincl("-v");
  2254. X#endif
  2255. X        break;
  2256. X    case 'x':
  2257. X#ifdef USETHREADS
  2258. X        s++;
  2259. X        if (*s == '=') s++;
  2260. X        if (*s <= '9' && *s >= '0') {
  2261. X        if ((max_tree_lines = atoi(s)) > 11)
  2262. X            max_tree_lines = 11;
  2263. X        do {
  2264. X            s++;
  2265. X        } while (*s <= '9' && *s >= '0');
  2266. X        } else
  2267. X        max_tree_lines = 6;
  2268. X        if (*s)
  2269. X        strncpy(select_order, s, 3);
  2270. X        use_threads = upordown;
  2271. X#else
  2272. X        notincl("-x");
  2273. X#endif
  2274. X        break;
  2275. X    case 'X':
  2276. X#ifdef USETHREADS
  2277. X        s++;
  2278. X        if (*s == '=') s++;
  2279. X        if (*s <= '9' && *s >= '0') {
  2280. X        select_on = atoi(s);
  2281. X        do {
  2282. X            s++;
  2283. X        } while (*s <= '9' && *s >= '0');
  2284. X        } else
  2285. X        select_on = upordown;
  2286. X        if (*s)
  2287. X        end_select = *s++;
  2288. X        if (*s)
  2289. X        page_select = *s;
  2290. X#else
  2291. X        notincl("-X");
  2292. X#endif
  2293. X        break;
  2294. X    /*
  2295. X     * People want a way to avoid checking for new newsgroups on startup.
  2296. X     */
  2297. X    case 'q':
  2298. X        quickstart = upordown;
  2299. X        break;
  2300. X    default:
  2301. X#ifdef VERBOSE
  2302. X        IF(verbose)
  2303. X        printf("\nIgnoring unrecognized switch: -%c\n", *s) FLUSH;
  2304. X        ELSE
  2305. X#endif
  2306. X#ifdef TERSE
  2307. X        printf("\nIgnoring -%c\n", *s) FLUSH;
  2308. X#endif
  2309. X        break;
  2310. X    }
  2311. X    }
  2312. X}
  2313. X
  2314. X/* print current switch values */
  2315. X
  2316. void
  2317. pr_switches()
  2318. X{
  2319. X    static char mp[2] = {'+','-'};
  2320. X    register int i;
  2321. X    
  2322. X    fputs("\nCurrent switch settings:\n",stdout);
  2323. X    printf("%c/ ", mp[strEQ(getval("SAVEDIR",SAVEDIR),"%p/%c")]);
  2324. X    printf("%ca ", mp[thread_always]);
  2325. X    printf("%cc ", mp[checkflag]);
  2326. X    printf("-C%d ", docheckwhen);
  2327. X    printf("-d%s ", cwd);
  2328. X#ifdef DEBUGGING
  2329. X    if (debug)
  2330. X    printf("-D%d ", debug);
  2331. X#endif
  2332. X    printf("%ce ", mp[erase_screen]);
  2333. X    printf("-F\"%s\" ", indstr);
  2334. X#ifdef INNERSEARCH
  2335. X    printf("-g%d", gline);
  2336. X#endif
  2337. X    putchar('\n');
  2338. X#ifdef VERBOSE
  2339. X    if (verbose) {
  2340. X    for (i=HEAD_FIRST; i<HEAD_LAST; i++)
  2341. X        printf("%ch%s%c",
  2342. X        mp[htype[i].ht_flags & HT_HIDE], htype[i].ht_name,
  2343. X        (! (i % 5) ? '\n' : ' ') );
  2344. X    }
  2345. X#endif
  2346. X    printf("-i%d ", initlines);
  2347. X    printf("%cl ", mp[muck_up_clear]);
  2348. X#ifdef CLEAREOL
  2349. X    printf("%cL ", mp[can_home_clear]);
  2350. X#endif /* CLEAREOL */
  2351. X    if (marking)
  2352. X    printf("-m%c ",marking==UNDERLINE?'u':'s');
  2353. X    else
  2354. X    printf("+m ");
  2355. X    printf("%cM ", mp[mbox_always]);
  2356. X    printf("%cN ", mp[norm_always]);
  2357. X    if (olden_days)
  2358. X    printf("-o%d ", olden_days);
  2359. X    else
  2360. X    printf("+o ");
  2361. X    printf("%cr ", mp[findlast]);
  2362. X    if (countdown)
  2363. X    printf("-s%d ", countdown);
  2364. X    else
  2365. X    printf("%cs ", mp[suppress_cn]);
  2366. X#ifdef ARTSEARCH
  2367. X    if (scanon)
  2368. X    printf("-S%d ",scanon);
  2369. X    else
  2370. X    printf("+S ");
  2371. X#endif
  2372. X#ifdef VERBOSE
  2373. X#ifdef TERSE
  2374. X    printf("%ct ", mp[!verbose]);
  2375. X#endif
  2376. X#endif
  2377. X    printf("%cT ", mp[typeahead]);
  2378. X#ifdef VERIFY
  2379. X    printf("%cv ", mp[verify]);
  2380. X#endif
  2381. X#ifdef USETHREADS
  2382. X    if (use_threads)
  2383. X    printf("-x%d%s ",max_tree_lines,select_order);
  2384. X    else
  2385. X    printf("+x ");
  2386. X    if (select_on)
  2387. X    printf("-X%d%c%c ",select_on,end_select,page_select);
  2388. X    else
  2389. X    printf("+X ");
  2390. X#endif
  2391. X    fputs("\n\n",stdout) FLUSH;
  2392. X#ifdef ONLY
  2393. X    if (maxngtodo) {
  2394. X#ifdef VERBOSE
  2395. X    IF(verbose)
  2396. X        fputs("Current restriction:",stdout);
  2397. X    ELSE
  2398. X#endif
  2399. X#ifdef TERSE
  2400. X        fputs("Only:",stdout);
  2401. X#endif
  2402. X    for (i=0; i<maxngtodo; i++)
  2403. X        printf(" %s",ngtodo[i]);
  2404. X    fputs("\n\n",stdout) FLUSH;
  2405. X    }
  2406. X#ifdef VERBOSE
  2407. X    else if (verbose)
  2408. X    fputs("No restriction.\n\n",stdout) FLUSH;
  2409. X#endif
  2410. X#endif
  2411. X}
  2412. X
  2413. void
  2414. cwd_check()
  2415. X{
  2416. X    char tmpbuf[LBUFLEN];
  2417. X
  2418. X    if (!cwd)
  2419. X    cwd = savestr(filexp("~/News"));
  2420. X    strcpy(tmpbuf,cwd);
  2421. X    if (chdir(cwd)) {
  2422. X    safecpy(tmpbuf,filexp(cwd),sizeof tmpbuf);
  2423. X    if (makedir(tmpbuf,MD_DIR) < 0 || chdir(tmpbuf) < 0) {
  2424. X        interp(cmd_buf, (sizeof cmd_buf), "%~/News");
  2425. X        if (makedir(cmd_buf,MD_DIR) < 0)
  2426. X        strcpy(tmpbuf,homedir);
  2427. X        else
  2428. X        strcpy(tmpbuf,cmd_buf);
  2429. X        chdir(tmpbuf);
  2430. X#ifdef VERBOSE
  2431. X        IF(verbose)
  2432. X        printf("\
  2433. Cannot make directory %s--\n\
  2434. X    articles will be saved to %s\n\
  2435. X\n\
  2436. X",cwd,tmpbuf) FLUSH;
  2437. X        ELSE
  2438. X#endif
  2439. X#ifdef TERSE
  2440. X        printf("\
  2441. Can't make %s--\n\
  2442. X    using %s\n\
  2443. X\n\
  2444. X",cwd,tmpbuf) FLUSH;
  2445. X#endif
  2446. X    }
  2447. X    }
  2448. X    free(cwd);
  2449. X    getwd(tmpbuf);
  2450. X    if (eaccess(tmpbuf,2)) {
  2451. X#ifdef VERBOSE
  2452. X    IF(verbose)
  2453. X        printf("\
  2454. Current directory %s is not writeable--\n\
  2455. X    articles will be saved to home directory\n\n\
  2456. X",tmpbuf) FLUSH;
  2457. X    ELSE
  2458. X#endif
  2459. X#ifdef TERSE
  2460. X        printf("%s not writeable--using ~\n\n",tmpbuf) FLUSH;
  2461. X#endif
  2462. X    strcpy(tmpbuf,homedir);
  2463. X    }
  2464. X    cwd = savestr(tmpbuf);
  2465. X}
  2466. END_OF_FILE
  2467. if test 12012 -ne `wc -c <'sw.c'`; then
  2468.     echo shar: \"'sw.c'\" unpacked with wrong size!
  2469. fi
  2470. # end of 'sw.c'
  2471. fi
  2472. if test -f 'unship.c' -a "${1}" != "-c" ; then 
  2473.   echo shar: Will not clobber existing file \"'unship.c'\"
  2474. else
  2475. echo shar: Extracting \"'unship.c'\" \(11690 characters\)
  2476. sed "s/^X//" >'unship.c' <<'END_OF_FILE'
  2477. X/* unship.c -- for unpacking ship files via trn */
  2478. X/* Based on ship.c -- Not copyrighted 1991 Mark Adler. */
  2479. X/* Modified by Wayne Davison, but still not copyrighted. */
  2480. X
  2481. X#include "EXTERN.h"
  2482. X#include "common.h"
  2483. X#include "respond.h"
  2484. X#include "decode.h"
  2485. X
  2486. typedef unsigned long ulg;    /* 32-bit unsigned integer */
  2487. X
  2488. X/* Function prototypes */
  2489. X
  2490. static void decode_line ANSI((unsigned char *));
  2491. static void err ANSI((int));
  2492. X
  2493. X/* Globals for ship() */
  2494. ulg ccnt;        /* count of bytes read or written */
  2495. ulg crc;        /* CRC register */
  2496. ulg buf4;        /* four byte buffer */
  2497. int bcnt;        /* buffer count */
  2498. X
  2499. unsigned int decb;    /* bit buffer for decode */
  2500. unsigned int decn;    /* number of bits in decb */
  2501. X
  2502. bool fast;        /* true for arithmetic coding, else base 85 */
  2503. bool overwrite = 1;    /* should we overwrite existing files? */
  2504. X
  2505. X/* Errors */
  2506. X#define SE_FORM 1
  2507. X#define SE_CONT 2
  2508. X#define SE_CRC 3
  2509. X#define SE_OVER 4
  2510. X#define SE_FULL 5
  2511. char *errors[] = {
  2512. X  /* 1 */ "Invalid ship format.",
  2513. X  /* 2 */ "This piece is out of sequence.",
  2514. X  /* 3 */ "CRC check failed.",
  2515. X  /* 4 */ "File already exists.",
  2516. X  /* 5 */ "Error writing file.",
  2517. X};
  2518. X
  2519. X/* Set of 86 characters used for the base 85 digits (last one not used), and
  2520. X   the 86 character arithmetic coding.    Selected to be part of both the ASCII
  2521. X   printable characters, and the common EBCDIC printable characters whose
  2522. X   ASCII translations are universal. */
  2523. unsigned char safe[] = {
  2524. X    '{','"','#','$','%','&','\'','(',')','*','+',',','-','.','/',
  2525. X    '0','1','2','3','4','5','6','7','8','9',':',';','<','=','>','?','@',
  2526. X    'A','B','C','D','E','F','G','H','I','J','K','L','M',
  2527. X    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z','_',
  2528. X    'a','b','c','d','e','f','g','h','i','j','k','l','m',
  2529. X    'n','o','p','q','r','s','t','u','v','w','x','y','z','}'};
  2530. X
  2531. X#define LOWSZ (sizeof(safe)-64)        /* low set size for fast coding */
  2532. X
  2533. X/* Special replacement pairs--if first of each pair is received, it is
  2534. X   treated like the second member of the pair.    You're probably
  2535. X   wondering why.  The first pair is for compatibility with an
  2536. X   earlier version of ship that used ! for the base 85 zero digit.
  2537. X   However, there exist ASCII-EBCDIC translation tables that don't
  2538. X   know about exclamation marks.  The second set has mysterious
  2539. X   historical origins that are best left unspoken ... */
  2540. unsigned char aliases[] = {'!','{','|','+',0};
  2541. X
  2542. X/* Inverse of safe[], filled in by unship_init() */
  2543. unsigned char invsafe[256];
  2544. X
  2545. X/* Table of CRC-32's of all single byte values (made by makecrc.c) */
  2546. ulg crctab[] = {
  2547. X  0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,
  2548. X  0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L,
  2549. X  0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L,
  2550. X  0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL,
  2551. X  0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L,
  2552. X  0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L,
  2553. X  0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L,
  2554. X  0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL,
  2555. X  0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L,
  2556. X  0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL,
  2557. X  0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L,
  2558. X  0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L,
  2559. X  0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L,
  2560. X  0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL,
  2561. X  0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL,
  2562. X  0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L,
  2563. X  0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL,
  2564. X  0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L,
  2565. X  0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L,
  2566. X  0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L,
  2567. X  0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL,
  2568. X  0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L,
  2569. X  0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L,
  2570. X  0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL,
  2571. X  0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L,
  2572. X  0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L,
  2573. X  0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L,
  2574. X  0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L,
  2575. X  0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L,
  2576. X  0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL,
  2577. X  0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL,
  2578. X  0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L,
  2579. X  0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L,
  2580. X  0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL,
  2581. X  0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL,
  2582. X  0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L,
  2583. X  0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL,
  2584. X  0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L,
  2585. X  0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL,
  2586. X  0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L,
  2587. X  0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL,
  2588. X  0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L,
  2589. X  0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L,
  2590. X  0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL,
  2591. X  0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L,
  2592. X  0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L,
  2593. X  0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L,
  2594. X  0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L,
  2595. X  0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L,
  2596. X  0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L,
  2597. X  0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL,
  2598. X  0x2d02ef8dL
  2599. X};
  2600. X
  2601. X/* Macro to update the CRC shift register one byte at a time */
  2602. X#define CRC(c,b) (crctab[((int)(c)^(int)(b))&0xff]^((c)>>8))
  2603. X
  2604. X/* cputc(d,x)--like putc(d,f), but delays four bytes and computes a CRC.
  2605. X   x is a cfile *, and d is expected to be an ulg. */
  2606. X#define cputf(fp) (int)(crc=CRC(crc,buf4),putc((int)buf4&0xff,fp),ccnt++)
  2607. X#define cputc(d,fp) (bcnt!=4?bcnt++:cputf(fp),buf4=(buf4>>8)+((ulg)(d)<<24))
  2608. X
  2609. X/* Build invsafe[], the inverse of safe[]. */
  2610. void
  2611. unship_init()
  2612. X{
  2613. X  int i;
  2614. X
  2615. X  for (i = 0; i < 256; i++)
  2616. X    invsafe[i] = 127;
  2617. X  for (i = 0; i < sizeof(safe); i++)
  2618. X    invsafe[safe[i]] = (char)i;
  2619. X  for (i = 0; aliases[i]; i += 2)
  2620. X    invsafe[aliases[i]] = invsafe[aliases[i + 1]];
  2621. X}
  2622. X
  2623. int
  2624. unship(in)
  2625. XFILE *in;
  2626. X{
  2627. X  int b;        /* state of line loop */
  2628. X  char l[LBUFLEN];    /* line buffer on input */
  2629. X  char *p;        /* modifies line buffer */
  2630. X  char *q;        /* scans continuation line */
  2631. X
  2632. X  /* Loop on the latest article's lines */
  2633. X  b = 2;                /* not in body yet */
  2634. X  while (1)                /* return on end of last file */
  2635. X  {
  2636. X    /* Get next line from file */
  2637. X    if (fgets(l, LBUFLEN, in) == Nullch)
  2638. X      break;
  2639. X
  2640. X    /* Strip control characters and leading blank space, if any */
  2641. X    for (q = l; *q && *q <= ' ' && *q != '\n'; q++)
  2642. X      ;
  2643. X    for (p = l; *q; q++)
  2644. X      if (*q >= ' ' || *q == '\n')
  2645. X    *p++ = *q;
  2646. X    *p = 0;
  2647. X
  2648. X    /* Based on current state, end or start on terminator.  States are:
  2649. X     b == 0:  at start of body or body terminator line
  2650. X     b == 1:  in middle of body line
  2651. X     b == 2:  at start of non-body line
  2652. X     b == 3:  in middle of non-body line
  2653. X     b == 4:  at information line
  2654. X    */
  2655. X    switch (b)
  2656. X    {
  2657. X    case 0:
  2658. X      if ((!fast && strEQ(l, "$\n")) ||
  2659. X      (fast && strEQ(l, "$ f\n")))
  2660. X      {
  2661. X    b = 4;
  2662. X    break;
  2663. X      }
  2664. X      /* fall through to case 1 */
  2665. X    case 1:
  2666. X      decode_line((unsigned char *)l);
  2667. X      b = l[strlen(l) - 1] != '\n';
  2668. X      break;
  2669. X    case 2:
  2670. X      if (strEQ(l, "$\n") || strEQ(l, "$ f\n"))
  2671. X      {
  2672. X    fast = l[1] == ' ';
  2673. X    b = 4;
  2674. X    break;
  2675. X      }
  2676. X      /* fall through to case 3 */
  2677. X    case 3:
  2678. X      b = l[strlen(l)-1] == '\n' ? 2 : 3;
  2679. X      break;
  2680. X    case 4:
  2681. X      /* Possible information lines are ship, more, cont, and end */
  2682. X      if (l[b = strlen(l) - 1] != '\n')
  2683. X      {
  2684. X    err(SE_FORM);
  2685. X    decode_end();
  2686. X    return -1;
  2687. X      }
  2688. X      l[b] = 0;
  2689. X      if (strnEQ(l, "ship ", 5))
  2690. X      {
  2691. X    /* get name, open new output file */
  2692. X    if (decode_fp != Nullfp)
  2693. X      decode_end();            /* outputs an "incomplete" warning */
  2694. X    if (strEQ(l + 5, "-"))
  2695. X      strcpy(decode_fname, "unnamed");
  2696. X    else
  2697. X      strcpy(decode_fname, l + 5);
  2698. X    sprintf(decode_dest, "%s/%s", extractdest, decode_fname);
  2699. X    printf("Decoding: %s\n", decode_fname);
  2700. X#ifndef VMS    /* shouldn't have explicit version #, so VMS won't overwrite */
  2701. X    if (!overwrite && (decode_fp = fopen(decode_dest, "r")) != Nullfp)
  2702. X    {
  2703. X      fclose(decode_fp);
  2704. X      decode_fp = Nullfp;
  2705. X      err(SE_OVER);
  2706. X      return -1;
  2707. X    }
  2708. X#endif /* !VMS */
  2709. X    if ((decode_fp = fopen(decode_dest, FOPEN_WB)) == Nullfp)
  2710. X    {
  2711. X      err(SE_FULL);
  2712. X      return -1;
  2713. X    }
  2714. X    crc = 0xffffffffL;        /* preload CRC register */
  2715. X    buf4 = 0;            /* empty fifo (for output) */
  2716. X    bcnt = 0;            /* fifo is empty (output) */
  2717. X    b = decb = decn = 0;
  2718. X    ccnt = 0;
  2719. X      }
  2720. X      else if (strEQ(l, "more"))
  2721. X      {
  2722. X    /* check if currently writing */
  2723. X    if (decode_fp == Nullfp)
  2724. X    {
  2725. X      err(SE_FORM);
  2726. X      return -1;
  2727. X    }
  2728. X    b = 2;
  2729. X      }
  2730. X      else if (strnEQ(l, "cont ", 5))
  2731. X      {
  2732. X    /* check name and file offset */
  2733. X    if (decode_fp == Nullfp)
  2734. X    {
  2735. X      err(SE_CONT);
  2736. X      return -1;
  2737. X    }
  2738. X    for (q = l + 5; *q && *q != ' '; q++)
  2739. X      ;
  2740. X    if (*q == 0 || atol(l + 5) != ccnt + 4 + (decn != 0) ||
  2741. X        strNE(q + 1, decode_fname))
  2742. X    {
  2743. X      err(SE_CONT);
  2744. X      return -1;
  2745. X    }
  2746. X    b = 0;
  2747. X      }
  2748. X      else if (strcmp(l, "end") == 0)
  2749. X      {
  2750. X    /* check crc, close output file */
  2751. X    if (decode_fp == Nullfp)
  2752. X    {
  2753. X      err(SE_FORM);
  2754. X      return -1;
  2755. X    }
  2756. X    if (bcnt != 4 || buf4 != ~crc)
  2757. X      err(SE_CRC);
  2758. X    else
  2759. X      printf("CRC verified -- Done.\n");
  2760. X    if (ferror(decode_fp) || fclose(decode_fp))
  2761. X    {
  2762. X      err(SE_FULL);
  2763. X      decode_end();
  2764. X      return -1;
  2765. X    }
  2766. X    decode_fp = Nullfp;
  2767. X    b = 2;
  2768. X      }
  2769. X      else
  2770. X      {
  2771. X    for (q = l; *q && *q != ' '; q++)
  2772. X      ;
  2773. X    *q = 0;
  2774. X    printf("Ignoring unsupported ship keyword: '%s'\n", l);
  2775. X    b = 4;
  2776. X      }
  2777. X      break;
  2778. X    }
  2779. X  }
  2780. X  if (!(b & 2)) {
  2781. X    err(SE_FORM);
  2782. X    return -1;
  2783. X  }
  2784. X  if (decode_fp)
  2785. X    printf("(Continued)\n");
  2786. X  return 0;
  2787. X}
  2788. X
  2789. X/* Decode s, a string of base 85 digits or, if fast is true, a string of safe
  2790. X   characters generated arithmetically, into its binary equivalent, writing
  2791. X   the result to decode_fp, using cputc(). */
  2792. static void
  2793. decode_line(s)
  2794. unsigned char *s;    /* data to decode */
  2795. X{
  2796. X  int b;        /* state of line loop, next character */
  2797. X  int k;        /* counts bits or digits read */
  2798. X  /* powers of 85 table for decoding */
  2799. X  static ulg m[] = {1L,85L,85L*85L,85L*85L*85L,85L*85L*85L*85L};
  2800. X
  2801. X  if (fast)
  2802. X  {
  2803. X    unsigned int d;    /* disperses bits */
  2804. X
  2805. X    d = decb;
  2806. X    k = decn;
  2807. X    while ((b = *s++) != 0)
  2808. X      if ((b = invsafe[b]) < sizeof(safe))
  2809. X      {
  2810. X    if (b < LOWSZ)
  2811. X    {
  2812. X      d |= b << k;
  2813. X      k += 7;
  2814. X    }
  2815. X    else if ((b -= LOWSZ) < LOWSZ)
  2816. X    {
  2817. X      d |= (b + 0x40) << k;
  2818. X      k += 7;
  2819. X    }
  2820. X    else
  2821. X    {
  2822. X      d |= b << k;
  2823. X      k += 6;
  2824. X    }
  2825. X    if (k >= 8)
  2826. X    {
  2827. X      cputc(d, decode_fp);
  2828. X      d >>= 8;
  2829. X      k -= 8;
  2830. X    }
  2831. X      }
  2832. X    decb = d;
  2833. X    decn = k;
  2834. X  }
  2835. X  else
  2836. X  {
  2837. X    ulg d;        /* disperses bytes */
  2838. X
  2839. X    d = k = 0;
  2840. X    while ((b = *s++) != 0)
  2841. X      if ((b = invsafe[b]) < 85)
  2842. X      {
  2843. X    d += m[k] * b;
  2844. X    if (++k == 5)
  2845. X    {
  2846. X      cputc(d, decode_fp);  d >>= 8;
  2847. X      cputc(d, decode_fp);  d >>= 8;
  2848. X      cputc(d, decode_fp);  d >>= 8;
  2849. X      cputc(d, decode_fp);
  2850. X      d = k = 0;
  2851. X    }
  2852. X      }
  2853. X    if (--k > 0)
  2854. X    {
  2855. X      while (--k)
  2856. X      {
  2857. X    cputc(d, decode_fp);
  2858. X    d >>= 8;
  2859. X      }
  2860. X      cputc(d, decode_fp);
  2861. X    }
  2862. X  }
  2863. X}
  2864. X
  2865. static void
  2866. err(n)
  2867. int n;            /* error number */
  2868. X{
  2869. X  if (n == SE_FULL)
  2870. X    perror("ship");
  2871. X  fputs(errors[n - 1], stdout);
  2872. X  putchar('\n') FLUSH;
  2873. X}
  2874. END_OF_FILE
  2875. if test 11690 -ne `wc -c <'unship.c'`; then
  2876.     echo shar: \"'unship.c'\" unpacked with wrong size!
  2877. fi
  2878. # end of 'unship.c'
  2879. fi
  2880. echo shar: End of archive 5 \(of 13\).
  2881. cp /dev/null ark5isdone
  2882. MISSING=""
  2883. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  2884.     if test ! -f ark${I}isdone ; then
  2885.     MISSING="${MISSING} ${I}"
  2886.     fi
  2887. done
  2888. if test "${MISSING}" = "" ; then
  2889.     echo You have unpacked all 13 archives.
  2890.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2891. else
  2892.     echo You still need to unpack the following archives:
  2893.     echo "        " ${MISSING}
  2894. fi
  2895. ##  End of shell archive.
  2896. exit 0
  2897.